efl

Форк
0
/
emile_image.c 
2546 строк · 73.5 Кб
1
#ifdef HAVE_CONFIG_H
2
#include <config.h>
3
#endif
4

5
#ifdef ENABLE_LIBLZ4
6
#include <lz4.h>
7
#else
8
#include "lz4.h"
9
#endif
10

11
#include <stdio.h>
12
#include <setjmp.h>
13
#include <jpeglib.h>
14
#include <jerror.h>
15

16
#include "rg_etc1.h"
17
#include "Emile.h"
18
#include "emile_private.h"
19

20
#ifdef BUILD_NEON
21
#include <arm_neon.h>
22
#endif
23

24
#define IMG_MAX_SIZE 65000
25

26
#define IMG_TOO_BIG(w, h)                                 \
27
  ((((unsigned long long)w) * ((unsigned long long)h)) >= \
28
   ((1ULL << (29 * (sizeof(void *) / 4))) - 2048))
29

30
#define SPANS_COMMON(x1, w1, x2, w2) \
31
  (!(((int)((x2) + (int)(w2)) <= (int)(x1)) || (int)((x2) >= (int)((x1) + (int)(w1)))))
32

33
#define RECTS_INTERSECT(x, y, w, h, xx, yy, ww, hh) \
34
  ((SPANS_COMMON((x), (w), (xx), (ww))) && (SPANS_COMMON((y), (h), (yy), (hh))))
35

36
#define RECTS_CLIP_TO_RECT(_x, _y, _w, _h, _cx, _cy, _cw, _ch)    \
37
  {                                                               \
38
     if (RECTS_INTERSECT(_x, _y, _w, _h, _cx, _cy, _cw, _ch))     \
39
       {                                                          \
40
          if ((int)_x < (int)(_cx))                               \
41
            {                                                     \
42
               if ((int)_w + ((int)_x - (int)(_cx)) < 0) _w = 0;  \
43
               else _w += ((int)_x - (int)(_cx));                 \
44
               _x = (_cx);                                        \
45
            }                                                     \
46
          if ((int)(_x + _w) > (int)((_cx) + (_cw)))              \
47
            _w = (_cx) + (_cw) - _x;                              \
48
          if ((int)_y < (int)(_cy))                               \
49
            {                                                     \
50
               if ((int)_h + ((int)_y - (int)(_cy)) < 0) _h = 0;  \
51
               else _h += ((int)_y - (int)(_cy));                 \
52
               _y = (_cy);                                        \
53
            }                                                     \
54
          if ((int)(_y + _h) > (int)((_cy) + (_ch)))              \
55
            _h = (_cy) + (_ch) - _y;                              \
56
       }                                                          \
57
     else                                                         \
58
       {                                                          \
59
          _w = 0; _h = 0;                                         \
60
       }                                                          \
61
  }
62

63
#ifndef WORDS_BIGENDIAN
64
/* x86 */
65
#define A_VAL(p) (((uint8_t *)(p))[3])
66
#define R_VAL(p) (((uint8_t *)(p))[2])
67
#define G_VAL(p) (((uint8_t *)(p))[1])
68
#define B_VAL(p) (((uint8_t *)(p))[0])
69
#else
70
/* ppc */
71
#define A_VAL(p) (((uint8_t *)(p))[0])
72
#define R_VAL(p) (((uint8_t *)(p))[1])
73
#define G_VAL(p) (((uint8_t *)(p))[2])
74
#define B_VAL(p) (((uint8_t *)(p))[3])
75
#endif
76

77
#define ARGB_JOIN(a, r, g, b) \
78
  (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
79

80
#define OFFSET_BLOCK_SIZE 4
81
#define OFFSET_ALGORITHM  5
82
#define OFFSET_OPTIONS    6
83
#define OFFSET_WIDTH      8
84
#define OFFSET_HEIGHT     12
85
#define OFFSET_BLOCKS     16
86

87
struct _Emile_Image
88
{
89
   Emile_Image_Load_Opts opts;
90

91
   struct
92
   {
93
      unsigned int width;
94
      unsigned int height;
95
   } size, block;
96

97
   Eina_Rectangle        region;
98

99
   union
100
   {
101
      Eina_Binbuf *bin;
102
      Eina_File   *f;
103
   } source;
104

105
   const unsigned char  *source_data;
106

107
   Eina_Bool             (*bind)(Emile_Image *image, Emile_Image_Load_Opts *opts, Emile_Image_Animated *animated, Emile_Image_Load_Error *error);
108
   Eina_Bool             (*head)(Emile_Image *image, Emile_Image_Property *prop, unsigned int property_size, Emile_Image_Load_Error *error);
109
   Eina_Bool             (*data)(Emile_Image *image, Emile_Image_Property *prop, unsigned int property_size, void *pixels, Emile_Image_Load_Error *error);
110
   void                  (*close)(Emile_Image *image);
111

112
   Emile_Action_Cb       cancelled;
113
   const void           *cancelled_data;
114

115
   Emile_Colorspace      cspace;
116

117
   Eina_Bool             bin_source : 1;
118

119
   /* TGV option */
120
   Eina_Bool             unpremul : 1;
121
   Eina_Bool             compress : 1;
122
   Eina_Bool             blockless : 1;
123
   Eina_Bool             load_opts : 1;
124
};
125

126
static inline Eina_Bool
127
_emile_image_cancelled_is(Emile_Image *image)
128
{
129
   if (!image->cancelled) return EINA_FALSE;
130
   return image->cancelled((void*) image->cancelled_data, image, EMILE_ACTION_CANCELLED);
131
}
132

133
#define EMILE_IMAGE_TASK_CHECK(Image, Count, Mask, Error, Error_Handler) \
134
  do {                                                                  \
135
     Count++;                                                           \
136
     if ((Count & Mask) == Mask)                                        \
137
       {                                                                \
138
          Count = 0;                                                    \
139
          if (_emile_image_cancelled_is(Image))                         \
140
            {                                                           \
141
               *Error = EMILE_IMAGE_LOAD_ERROR_CANCELLED;               \
142
               goto Error_Handler;                                      \
143
            }                                                           \
144
       }                                                                \
145
  } while (0);
146

147
static const unsigned char *
148
_emile_image_file_source_map(Emile_Image *image, unsigned int *length)
149
{
150
   if (!image)
151
     return NULL;
152

153
   if (image->bin_source)
154
     {
155
        if (length)
156
          *length = eina_binbuf_length_get(image->source.bin);
157
        return eina_binbuf_string_get(image->source.bin);
158
     }
159

160
   if (length)
161
     *length = eina_file_size_get(image->source.f);
162
   if (!image->source_data)
163
     {
164
        image->source_data = eina_file_map_all(image->source.f, EINA_FILE_SEQUENTIAL);
165
     }
166
   return image->source_data;
167
}
168

169
static void
170
_emile_image_file_source_unmap(Emile_Image *image)
171
{
172
   if (!(image && image->source_data))
173
     return;
174
   eina_file_map_free(image->source.f, (void *)image->source_data);
175
   image->source_data = NULL;
176
}
177

178
static int
179
_roundup(int val, int rup)
180
{
181
   if (val >= 0 && rup > 0)
182
     return (val + rup - 1) - ((val + rup - 1) % rup);
183
   return 0;
184
}
185

186
/* TGV Handling */
187

188
static const Emile_Colorspace cspaces_etc1[] = {
189
   EMILE_COLORSPACE_ETC1,
190
   EMILE_COLORSPACE_RGB8_ETC2,
191
   EMILE_COLORSPACE_ARGB8888
192
};
193

194
static const Emile_Colorspace cspaces_rgb8_etc2[] = {
195
   EMILE_COLORSPACE_RGB8_ETC2,
196
   EMILE_COLORSPACE_ARGB8888
197
};
198

199
static const Emile_Colorspace cspaces_rgba8_etc2_eac[] = {
200
   EMILE_COLORSPACE_RGBA8_ETC2_EAC,
201
   EMILE_COLORSPACE_ARGB8888
202
};
203

204
static const Emile_Colorspace cspaces_etc1_alpha[] = {
205
   EMILE_COLORSPACE_ETC1_ALPHA,
206
   EMILE_COLORSPACE_ARGB8888
207
};
208

209
static const Emile_Colorspace cspaces_gry[] = {
210
   EMILE_COLORSPACE_GRY8,
211
   EMILE_COLORSPACE_AGRY88,
212
   EMILE_COLORSPACE_ARGB8888
213
};
214

215
/**************************************************************
216
* The TGV file format is oriented around compression mecanism
217
* that hardware are good at decompressing. We do still provide
218
* a fully software implementation in case your hardware doesn't
219
* handle it. As OpenGL is pretty bad at handling border of
220
* texture, we do duplicate the first pixels of every border.
221
*
222
* This file format is designed to compress/decompress things
223
* in block area. Giving opportunity to store really huge file
224
* and only decompress/compress them as we need. Note that region
225
* only work with software decompression as we don't have a sane
226
* way to duplicate border to avoid artifact when scaling texture.
227
*
228
* The file format is as follow :
229
* - char     magic[4]: "TGV1"
230
* - uint8_t  block_size (real block size = (4 << bits[0-3], 4 << bits[4-7])
231
* - uint8_t  algorithm (0 -> ETC1, 1 -> ETC2 RGB, 2 -> ETC2 RGBA, 3 -> ETC1+Alpha)
232
* - uint8_t  options[2] (bitmask: 1 -> lz4, 2 for block-less, 4 -> unpremultiplied)
233
* - uint32_t width
234
* - uint32_t height
235
* - blocks[]
236
*   - 0 length encoded compress size (if length == 64 * block_size => no compression)
237
*   - lzma encoded etc1 block
238
*
239
* If the format is ETC1+Alpha (algo = 3), then a second image is encoded
240
* in ETC1 right after the first one, and it contains grey-scale alpha
241
* values.
242
**************************************************************/
243

244
// FIXME: wondering if we should support mipmap
245
// TODO: support ETC1+ETC2 images (RGB only)
246

247
static Eina_Bool
248
_emile_tgv_bind(Emile_Image *image,
249
                Emile_Image_Load_Opts *opts EINA_UNUSED,
250
                Emile_Image_Animated *animated EINA_UNUSED,
251
                Emile_Image_Load_Error *error)
252
{
253
   const unsigned char *m;
254
   unsigned int length;
255

256
   m = _emile_image_file_source_map(image, &length);
257
   if (!m)
258
     return EINA_FALSE;
259

260
   /* Fast check for file characteristic (useful when trying to guess
261
      a file format without extention). */
262
   if (length < 16 || strncmp((const char *)m, "TGV1", 4) != 0)
263
     goto on_error;
264

265
   if ((m[OFFSET_ALGORITHM] & 0xFF) > 3)
266
     goto on_error;
267

268
   return EINA_TRUE;
269

270
on_error:
271
   *error = EMILE_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT;
272
   _emile_image_file_source_unmap(image);
273
   return EINA_FALSE;
274
}
275

276
static Eina_Bool
277
_emile_tgv_head(Emile_Image *image,
278
                Emile_Image_Property *prop,
279
                unsigned int property_size,
280
                Emile_Image_Load_Error *error)
281
{
282
   const unsigned char *m;
283
   unsigned int length;
284

285
   m = _emile_image_file_source_map(image, &length);
286
   if (!m)
287
     return EINA_FALSE;
288

289
   /* This can be used for later ABI change of the structure. */
290
   if (sizeof(Emile_Image_Property) != property_size)
291
     return EINA_FALSE;
292

293
   switch (m[OFFSET_ALGORITHM] & 0xFF)
294
     {
295
      case 0:
296
        prop->cspaces = cspaces_etc1;
297
        prop->alpha = EINA_FALSE;
298
        image->cspace = EMILE_COLORSPACE_ETC1;
299
        break;
300

301
      case 1:
302
        prop->cspaces = cspaces_rgb8_etc2;
303
        prop->alpha = EINA_FALSE;
304
        image->cspace = EMILE_COLORSPACE_RGB8_ETC2;
305
        break;
306

307
      case 2:
308
        prop->cspaces = cspaces_rgba8_etc2_eac;
309
        prop->alpha = EINA_TRUE;
310
        image->cspace = EMILE_COLORSPACE_RGBA8_ETC2_EAC;
311
        break;
312

313
      case 3:
314
        prop->cspaces = cspaces_etc1_alpha;
315
        prop->alpha = EINA_TRUE;
316
        prop->premul = !!(m[OFFSET_OPTIONS] & 0x4);
317
        image->unpremul = prop->premul;
318
        image->cspace = EMILE_COLORSPACE_ETC1_ALPHA;
319
        break;
320

321
      default:
322
        *error = EMILE_IMAGE_LOAD_ERROR_CORRUPT_FILE;
323
        return EINA_FALSE;
324
     }
325

326
   image->compress = m[OFFSET_OPTIONS] & 0x1;
327
   image->blockless = (m[OFFSET_OPTIONS] & 0x2) != 0;
328

329
   image->size.width = eina_ntohl(*((unsigned int *)&(m[OFFSET_WIDTH])));
330
   image->size.height = eina_ntohl(*((unsigned int *)&(m[OFFSET_HEIGHT])));
331

332
   if (image->blockless)
333
     {
334
        image->block.width = _roundup(image->size.width + 2, 4);
335
        image->block.height = _roundup(image->size.height + 2, 4);
336
     }
337
   else
338
     {
339
        image->block.width = 4 << (m[OFFSET_BLOCK_SIZE] & 0x0f);
340
        image->block.height = 4 << ((m[OFFSET_BLOCK_SIZE] & 0xf0) >> 4);
341
     }
342

343
   EINA_RECTANGLE_SET(&image->region,
344
                      0, 0,
345
                      image->size.width, image->size.height);
346
   if (image->load_opts &&
347
       ((image->opts.region.w > 0) && (image->opts.region.h > 0) &&
348
        (image->opts.region.w != (int) image->size.width) &&
349
        (image->opts.region.h != (int) image->size.height)))
350
     {
351
        /* ETC colorspace doesn't work with region for now */
352
        prop->cspaces = NULL;
353

354
        if (!eina_rectangle_intersection(&image->region, &image->opts.region))
355
          {
356
             *error = EMILE_IMAGE_LOAD_ERROR_GENERIC;
357
             return EINA_FALSE;
358
          }
359
     }
360

361
   prop->w = image->size.width;
362
   prop->h = image->size.height;
363
   prop->borders.l = 1;
364
   prop->borders.t = 1;
365
   prop->borders.r = _roundup(prop->w + 2, 4) - prop->w - 1;
366
   prop->borders.b = _roundup(prop->h + 2, 4) - prop->h - 1;
367

368
   return EINA_TRUE;
369
}
370

371
static inline unsigned int
372
_tgv_length_get(const unsigned char *m,
373
                unsigned int length,
374
                unsigned int *offset)
375
{
376
   unsigned int r = 0;
377
   unsigned int shift = 0;
378

379
   while (*offset < length && ((*m) & 0x80))
380
     {
381
        r = r | (((*m) & 0x7F) << shift);
382
        shift += 7;
383
        m++;
384
        (*offset)++;
385
     }
386
   if (*offset < length)
387
     {
388
        r = r | (((*m) & 0x7F) << shift);
389
        (*offset)++;
390
     }
391

392
   return r;
393
}
394

395
static Eina_Bool
396
_emile_tgv_data(Emile_Image *image,
397
                Emile_Image_Property *prop,
398
                unsigned int property_size,
399
                void *pixels,
400
                Emile_Image_Load_Error *error)
401
{
402
   const unsigned char *m;
403
   unsigned int *p = pixels;
404
   unsigned char *p_etc = pixels;
405
   Eina_Binbuf *buffer = NULL;
406
   Eina_Rectangle master;
407
   unsigned int block_length;
408
   unsigned int length, offset;
409
   unsigned int x, y;
410
   unsigned int block_count;
411
   unsigned int etc_width = 0;
412
   unsigned int etc_block_size;
413
   int num_planes = 1, plane, alpha_offset = 0;
414
   Eina_Bool r = EINA_FALSE;
415

416
   m = _emile_image_file_source_map(image, &length);
417
   if (!m)
418
     {
419
        *error = EMILE_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
420
        return EINA_FALSE;
421
     }
422

423
   if (sizeof(Emile_Image_Property) != property_size)
424
     return EINA_FALSE;
425

426
   offset = OFFSET_BLOCKS;
427

428
   *error = EMILE_IMAGE_LOAD_ERROR_CORRUPT_FILE;
429

430
   /* By definition, prop{.w, .h} == region{.w, .h} */
431
   EINA_RECTANGLE_SET(&master,
432
                      image->region.x, image->region.y,
433
                      prop->w, prop->h);
434

435
   switch (image->cspace)
436
     {
437
      case EMILE_COLORSPACE_ETC1:
438
      case EMILE_COLORSPACE_RGB8_ETC2:
439
        etc_block_size = 8;
440
        break;
441

442
      case EMILE_COLORSPACE_RGBA8_ETC2_EAC:
443
        etc_block_size = 16;
444
        break;
445

446
      case EMILE_COLORSPACE_ETC1_ALPHA:
447
        etc_block_size = 8;
448
        num_planes = 2;
449
        alpha_offset = ((prop->w + 2 + 3) / 4) * ((prop->h + 2 + 3) / 4) * 8 / sizeof(*p_etc);
450
        break;
451

452
      default:
453
        abort();
454
     }
455
   etc_width = ((prop->w + 2 + 3) / 4) * etc_block_size;
456

457
   switch (prop->cspace)
458
     {
459
      case EMILE_COLORSPACE_ETC1:
460
      case EMILE_COLORSPACE_RGB8_ETC2:
461
      case EMILE_COLORSPACE_RGBA8_ETC2_EAC:
462
      case EMILE_COLORSPACE_ETC1_ALPHA:
463
        if (master.x % 4 || master.y % 4)
464
          // FIXME: Should we really abort here ? Seems like a late check for me
465
          abort();
466
        break;
467

468
      case EMILE_COLORSPACE_ARGB8888:
469
        /* Offset to take duplicated pixels into account */
470
        master.x += 1;
471
        master.y += 1;
472
        break;
473

474
      default:
475
        abort();
476
     }
477

478
   if (prop->cspace != EMILE_COLORSPACE_ARGB8888 &&
479
       prop->cspace != image->cspace)
480
     {
481
        if (!((prop->cspace == EMILE_COLORSPACE_RGB8_ETC2) &&
482
              (image->cspace == EMILE_COLORSPACE_ETC1)))
483
          {
484
             *error = EMILE_IMAGE_LOAD_ERROR_GENERIC;
485
             return EINA_FALSE;
486
          }
487
        /* else: ETC2 is compatible with ETC1 and is preferred */
488
     }
489

490
   /* Allocate space for each ETC block (8 or 16 bytes per 4 * 4 pixels group) */
491
   block_count = image->block.width * image->block.height / (4 * 4);
492
   if (image->compress)
493
     buffer = eina_binbuf_manage_new(alloca(etc_block_size * block_count),
494
                                     etc_block_size * block_count,
495
                                     EINA_TRUE);
496

497
   for (plane = 0; plane < num_planes; plane++)
498
     for (y = 0; y < image->size.height + 2; y += image->block.height)
499
       for (x = 0; x < image->size.width + 2; x += image->block.width)
500
         {
501
            Eina_Rectangle current;
502
            Eina_Binbuf *data_start;
503
            const unsigned char *it;
504
            unsigned int i, j;
505

506
            block_length = _tgv_length_get(m + offset, length, &offset);
507

508
            if (block_length == 0)
509
              {
510
                 *error = EMILE_IMAGE_LOAD_ERROR_CORRUPT_FILE;
511
                 goto on_error;
512
              }
513

514
            data_start = eina_binbuf_manage_new(m + offset,
515
                                                block_length,
516
                                                EINA_TRUE);
517
            offset += block_length;
518

519
            EINA_RECTANGLE_SET(&current,
520
                               x, y,
521
                               image->block.width, image->block.height);
522

523
            if (!eina_rectangle_intersection(&current, &master))
524
              {
525
                 eina_binbuf_free(data_start);
526
                 continue;
527
              }
528

529
            if (image->compress)
530
              {
531
                 if (!emile_expand(data_start, buffer, EMILE_LZ4HC))
532
                   {
533
                      eina_binbuf_free(data_start);
534
                      goto on_error;
535
                   }
536
              }
537
            else
538
              {
539
                 buffer = data_start;
540
                 if (block_count * etc_block_size != block_length)
541
                   {
542
                      eina_binbuf_free(data_start);
543
                      goto on_error;
544
                   }
545
              }
546
            it = eina_binbuf_string_get(buffer);
547

548
            for (i = 0; i < image->block.height; i += 4)
549
              for (j = 0; j < image->block.width; j += 4, it += etc_block_size)
550
                {
551
                   Eina_Rectangle current_etc;
552
                   unsigned int temporary[4 * 4];
553
                   unsigned int offset_x, offset_y;
554
                   int k, l;
555

556
                   EINA_RECTANGLE_SET(&current_etc, x + j, y + i, 4, 4);
557

558
                   if (!eina_rectangle_intersection(&current_etc, &current))
559
                     continue;
560

561
                   switch (prop->cspace)
562
                     {
563
                      case EMILE_COLORSPACE_ARGB8888:
564
                        switch (image->cspace)
565
                          {
566
                           case EMILE_COLORSPACE_ETC1:
567
                           case EMILE_COLORSPACE_ETC1_ALPHA:
568
                             if (!rg_etc1_unpack_block(it, temporary, 0))
569
                               {
570
                                  // TODO: Should we decode as RGB8_ETC2?
571
                                  fprintf(stderr, "ETC1: Block starting at {%i, %i} is corrupted!\n", x + j, y + i);
572
                                  continue;
573
                               }
574
                             break;
575

576
                           case EMILE_COLORSPACE_RGB8_ETC2:
577
                             rg_etc2_rgb8_decode_block((uint8_t *)it, temporary);
578
                             break;
579

580
                           case EMILE_COLORSPACE_RGBA8_ETC2_EAC:
581
                             rg_etc2_rgba8_decode_block((uint8_t *)it, temporary);
582
                             break;
583

584
                           default:
585
                             abort();
586
                          }
587

588
                        offset_x = current_etc.x - x - j;
589
                        offset_y = current_etc.y - y - i;
590

591
                        if (!plane)
592
                          {
593
#ifdef BUILD_NEON
594
                             if (eina_cpu_features_get() & EINA_CPU_NEON)
595
                               {
596
                                  uint32_t *dst = &p[current_etc.x - 1 + (current_etc.y - 1) * master.w];
597
                                  uint32_t *src = &temporary[offset_x + offset_y * 4];
598
                                  for (k = 0; k < current_etc.h; k++)
599
                                    {
600
                                       if (current_etc.w == 4)
601
                                         vst1q_u32(dst, vld1q_u32(src));
602
                                       else if (current_etc.w == 3)
603
                                         {
604
                                            vst1_u32(dst, vld1_u32(src));
605
                                            *(dst + 2) = *(src + 2);
606
                                         }
607
                                       else if (current_etc.w == 2)
608
                                         vst1_u32(dst, vld1_u32(src));
609
                                       else
610
                                         *dst = *src;
611
                                       dst += master.w;
612
                                       src += 4;
613
                                    }
614
                               }
615
                             else
616
#endif
617
                             for (k = 0; k < current_etc.h; k++)
618
                               {
619
                                  memcpy(&p[current_etc.x - 1 + (current_etc.y - 1 + k) * master.w],
620
                                         &temporary[offset_x + (offset_y + k) * 4],
621
                                         current_etc.w * sizeof(unsigned int));
622
                               }
623
                          }
624
                        else
625
                          {
626
                             for (k = 0; k < current_etc.h; k++)
627
                               for (l = 0; l < current_etc.w; l++)
628
                                 {
629
                                    unsigned int *rgbdata = &p[current_etc.x - 1 + (current_etc.y - 1 + k) * master.w + l];
630
                                    unsigned int *adata = &temporary[offset_x + (offset_y + k) * 4 + l];
631
                                    A_VAL(rgbdata) = G_VAL(adata);
632
                                 }
633
                          }
634
                        break;
635

636
                      case EMILE_COLORSPACE_ETC1:
637
                      case EMILE_COLORSPACE_RGB8_ETC2:
638
                      case EMILE_COLORSPACE_RGBA8_ETC2_EAC:
639
                        memcpy(&p_etc[(current_etc.x / 4) * etc_block_size + (current_etc.y / 4) * etc_width],
640
                               it,
641
                               etc_block_size);
642
                        break;
643

644
                      case EMILE_COLORSPACE_ETC1_ALPHA:
645
                        memcpy(&p_etc[(current_etc.x / 4) * etc_block_size + (current_etc.y / 4) * etc_width + plane * alpha_offset],
646
                               it,
647
                               etc_block_size);
648
                        break;
649

650
                      default:
651
                        abort();
652
                     }
653
                } /* bx,by inside blocks */
654

655
            eina_binbuf_free(data_start);
656
         } /* x,y macroblocks */
657

658
   // TODO: Add support for more unpremultiplied modes (ETC2)
659
   if (prop->cspace == EMILE_COLORSPACE_ARGB8888)
660
     prop->premul = image->unpremul;  /* call premul if unpremul data */
661

662
   *error = EMILE_IMAGE_LOAD_ERROR_NONE;
663
   r = EINA_TRUE;
664

665
on_error:
666
   if (image->compress) eina_binbuf_free(buffer);
667
   _emile_image_file_source_unmap(image);
668
   return r;
669
}
670

671
static void
672
_emile_tgv_close(Emile_Image *image EINA_UNUSED)
673
{
674
   /* TGV file loader doesn't keep any data allocated around */
675
}
676

677
/* JPEG Handling */
678

679
typedef struct _JPEG_error_mgr *emptr;
680
struct _JPEG_error_mgr
681
{
682
   struct jpeg_error_mgr pub;
683
   jmp_buf               setjmp_buffer;
684
};
685

686
struct jpeg_membuf_src
687
{
688
   struct jpeg_source_mgr  pub;
689

690
   const unsigned char    *buf;
691
   size_t                  len;
692
   struct jpeg_membuf_src *self;
693
};
694

695
static void
696
_emile_image_jpeg_error_exit_cb(j_common_ptr cinfo)
697
{
698
   char buffer[JMSG_LENGTH_MAX];
699
   emptr errmgr;
700

701
   // Avoid message "Not a JPEG file: starts with 0x%02x 0x%02x"
702
   if (cinfo->client_data || (cinfo->err->msg_code != JERR_NO_SOI))
703
     {
704
        (*cinfo->err->format_message)(cinfo, buffer);
705
        ERR("%s", buffer);
706
     }
707
   errmgr = (emptr)cinfo->err;
708
   longjmp(errmgr->setjmp_buffer, 1);
709
}
710

711
static void
712
_emile_image_jpeg_emit_message_cb(j_common_ptr cinfo, int msg_level)
713
{
714
   char buffer[JMSG_LENGTH_MAX];
715
   struct jpeg_error_mgr *err;
716

717
   err = cinfo->err;
718
   if (msg_level < 0)
719
     {
720
        if ((err->num_warnings == 0) || (err->trace_level >= 3))
721
          {
722
             (*cinfo->err->format_message)(cinfo, buffer);
723
             WRN("%s", buffer);
724
          }
725
        err->num_warnings++;
726
     }
727
   else
728
     {
729
        if (err->trace_level >= msg_level)
730
          {
731
             (*cinfo->err->format_message)(cinfo, buffer);
732
             INF("%s", buffer);
733
          }
734
     }
735
}
736

737
static void
738
_emile_image_jpeg_output_message_cb(j_common_ptr cinfo)
739
{
740
   char buffer[JMSG_LENGTH_MAX];
741

742
   (*cinfo->err->format_message)(cinfo, buffer);
743
   ERR("%s", buffer);
744
}
745

746
static void
747
_emile_jpeg_membuf_src_init(j_decompress_ptr cinfo EINA_UNUSED)
748
{
749
}
750

751
static boolean
752
_emile_jpeg_membuf_src_fill(j_decompress_ptr cinfo)
753
{
754
   static const JOCTET jpeg_eoi[2] = { 0xFF, JPEG_EOI };
755
   struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
756

757
   src->pub.bytes_in_buffer = sizeof(jpeg_eoi);
758
   src->pub.next_input_byte = jpeg_eoi;
759

760
   return TRUE;
761
}
762

763
static void
764
_emile_jpeg_membuf_src_skip(j_decompress_ptr cinfo, long num_bytes)
765
{
766
   struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
767

768
   if ((((long)src->pub.bytes_in_buffer - (long)src->len) > num_bytes) ||
769
       ((long)src->pub.bytes_in_buffer < num_bytes))
770
     {
771
        (*(cinfo)->err->error_exit)((j_common_ptr)(cinfo));
772
        return;
773
     }
774
   src->pub.bytes_in_buffer -= num_bytes;
775
   src->pub.next_input_byte += num_bytes;
776
}
777

778
static void
779
_emile_jpeg_membuf_src_term(j_decompress_ptr cinfo)
780
{
781
   struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
782
   if (!src)
783
     return;
784
   free(src);
785
   cinfo->src = NULL;
786
}
787

788
static int
789
_emile_jpeg_membuf_src(j_decompress_ptr cinfo, const void *map, size_t length)
790
{
791
   struct jpeg_membuf_src *src;
792

793
   src = calloc(1, sizeof(*src));
794
   if (!src)
795
     return -1;
796

797
   src->self = src;
798

799
   cinfo->src = &src->pub;
800
   src->buf = map;
801
   src->len = length;
802
   src->pub.init_source = _emile_jpeg_membuf_src_init;
803
   src->pub.fill_input_buffer = _emile_jpeg_membuf_src_fill;
804
   src->pub.skip_input_data = _emile_jpeg_membuf_src_skip;
805
   src->pub.resync_to_restart = jpeg_resync_to_restart;
806
   src->pub.term_source = _emile_jpeg_membuf_src_term;
807
   src->pub.bytes_in_buffer = src->len;
808
   src->pub.next_input_byte = src->buf;
809

810
   return 0;
811
}
812

813
/*! Magic number for EXIF header, App0, App1*/
814
static const unsigned char ExifHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
815
static const unsigned char JfifHeader[] = { 0x4A, 0x46, 0x49, 0x46, 0x00 };
816
static const unsigned char JfxxHeader[] = { 0x4A, 0x46, 0x58, 0x58, 0x00 };
817
static const unsigned char App0[] = { 0xff, 0xe0 };
818
static const unsigned char App1[] = { 0xff, 0xe1 };
819
static const unsigned char II[] = { 0x49, 0x49 };
820
static const unsigned char MM[] = { 0x4d, 0x4d };
821

822
typedef enum
823
{
824
   EXIF_BYTE_ALIGN_II,
825
   EXIF_BYTE_ALIGN_MM
826
} ExifByteAlign;
827

828
static Eina_Bool
829
_get_next_app0(const unsigned char *map, size_t fsize, size_t *position)
830
{
831
   unsigned short length = 0;
832
   unsigned int w = 0, h = 0;
833
   unsigned int format = 0;
834
   unsigned int data_size = 0;
835
   const unsigned char *app0_head, *p;
836

837
   /* header_mark:2, length:2, identifier:5 version:2, unit:1, den=4 thum=2 */
838
   if ((*position + 16) >= fsize)
839
     return EINA_FALSE;
840
   app0_head = map + *position;
841

842
   /* p is appn's start pointer excluding app0 marker */
843
   p = app0_head + 2;
844

845
   length = ((*p << 8) + *(p + 1));
846

847
   /* JFIF segment format */
848
   if (!memcmp(p + 2, JfifHeader, sizeof(JfifHeader)))
849
     {
850
        format = 3;
851
        w = *(p + 14);
852
        h = *(p + 15);
853
     }
854
   else if (!memcmp(p + 2, JfxxHeader, sizeof(JfxxHeader)))
855
     {
856
        if (*(p + 7) == 0x11)
857
          format = 1;
858
        else
859
          format = 3;
860
        w = *(p + 8);
861
        h = *(p + 9);
862
     }
863

864
   data_size = format * w * h;
865

866
   if ((*position + 2 + length + data_size) > fsize)
867
     return EINA_FALSE;
868

869
   *position = *position + 2 + length + data_size;
870

871
   return EINA_TRUE;
872
}
873

874
/* If app1 data is abnormal, returns EINA_FALSE.
875
   If app1 data is normal, returns EINA_TRUE.
876
   If app1 data is normal but not orientation data, orientation value is -1.
877
 */
878

879
static Eina_Bool
880
_get_orientation_app1(const unsigned char *map,
881
                      size_t fsize,
882
                      size_t *position,
883
                      int *orientation_res,
884
                      Eina_Bool *flipped)
885
{
886
   const unsigned char *app1_head, *buf;
887
   unsigned char orientation[2];  //orientation tag
888
   ExifByteAlign byte_align;
889
   unsigned int num_directory = 0;
890
   unsigned int ifd_offset = 10; //IFD offset start at 10th byte (mark:2 + data_size:2 + exif:6)
891
   unsigned int i, j;
892
   int direction;
893
   unsigned int data_size = 0;
894

895
   /* app1 mark:2, data_size:2, exif:6 tiff:8 */
896
   if ((*position + 18) >= fsize)
897
     return EINA_FALSE;
898
   app1_head = map + *position;
899
   buf = app1_head;
900

901
   data_size = ((*(buf + 2) << 8) + *(buf + 3));
902
   if ((*position + 2 + data_size) > fsize)
903
     return EINA_FALSE;
904

905
   if (memcmp(buf + 4, ExifHeader, sizeof(ExifHeader)))
906
     {
907
        *position = *position + 2 + data_size;
908
        *orientation_res = -1;
909
        return EINA_TRUE;
910
     }
911

912
   /* 2. get 10&11 byte  get info of "II(0x4949)" or "MM(0x4d4d)" */
913
   /* 3. get 14th - 17th byte get info for IFD offset */
914
   /* 4. get directory entry IFD */
915

916

917
   if (!memcmp(buf + 10, MM, sizeof(MM)))
918
     {
919
        // get 4byte by little endian
920
        ifd_offset += (*(buf + 14) << 24) + (*(buf + 15) << 16) + (*(buf + 16) << 8) + (*(buf + 17));
921

922
        if (ifd_offset > fsize)
923
          return EINA_FALSE;
924

925
        byte_align = EXIF_BYTE_ALIGN_MM;
926
        num_directory = ((*(buf + ifd_offset) << 8) + *(buf + ifd_offset + 1));
927
        orientation[0] = 0x01;
928
        orientation[1] = 0x12;
929
     }
930
   else if (!memcmp(buf + 10, II, sizeof(II)))
931
     {
932
        // get 4byte by big endian
933
        ifd_offset += (*(buf + 14))  + (*(buf + 15) << 8) + (*(buf + 16) << 16) + (*(buf + 17) << 24);
934

935
        if (ifd_offset > fsize)
936
          return EINA_FALSE;
937

938
        byte_align = EXIF_BYTE_ALIGN_II;
939
        num_directory = ((*(buf + ifd_offset + 1) << 8) + *(buf + ifd_offset));
940
        orientation[0] = 0x12;
941
        orientation[1] = 0x01;
942
     }
943
   else
944
     return EINA_FALSE;
945

946
   /* check num_directory data */
947
   if ((*position + (12 * num_directory + 20)) > fsize)
948
     return EINA_FALSE;
949

950
   buf = app1_head + ifd_offset + 2;  //next to 0th ifd (1st tag)
951

952
   j = 0;
953

954
   for (i = 0; i < num_directory; i++)
955
     {
956
        if (!memcmp(buf + j, orientation, 2))
957
          {
958
             /*get orientation tag */
959
             if (byte_align == EXIF_BYTE_ALIGN_MM)
960
               direction = *(buf + j + 9);
961
             else
962
               direction = *(buf + j + 8);
963
             switch (direction)
964
               {
965
                case 3:
966
                  *orientation_res = 180;
967
                  *flipped = EINA_FALSE;
968
                  return EINA_TRUE;
969

970
                case 4:
971
                  *orientation_res = 180;
972
                  *flipped = EINA_TRUE;
973
                  return EINA_TRUE;
974

975
                case 6:
976
                  *orientation_res = 90;
977
                  *flipped = EINA_FALSE;
978
                  return EINA_TRUE;
979

980
                case 7:
981
                  *orientation_res = 90;
982
                  *flipped = EINA_TRUE;
983
                  return EINA_TRUE;
984

985
                case 5:
986
                  *orientation_res = 270;
987
                  *flipped = EINA_TRUE;
988
                  return EINA_TRUE;
989

990
                case 8:
991
                  *orientation_res = 270;
992
                  *flipped = EINA_FALSE;
993
                  return EINA_TRUE;
994

995
                case 2:
996
                  *orientation_res = 0;
997
                  *flipped = EINA_TRUE;
998
                  return EINA_TRUE;
999

1000
                default:
1001
                  *orientation_res = 0;
1002
                  *flipped = EINA_FALSE;
1003
                  return EINA_TRUE;
1004
               }
1005
          }
1006
        else
1007
          j = j + 12;
1008
     }
1009
   return EINA_FALSE;
1010
}
1011

1012
static int
1013
_get_orientation(const void *map, size_t length, Eina_Bool *flipped)
1014
{
1015
   unsigned char *buf;
1016
   size_t position = 0;
1017
   int orientation = -1;
1018
   Eina_Bool res = EINA_FALSE;
1019

1020
   *flipped = EINA_FALSE;
1021

1022
   /* open file and get 22 byte frome file */
1023
   if (!map)
1024
     return 0;
1025
   /* 1. read 22byte */
1026
   if (length < 22)
1027
     return 0;
1028
   buf = (unsigned char *)map;
1029

1030
   position = 2;
1031
   /* 2. check 2,3 bypte with APP0(0xFFE0) or APP1(0xFFE1) */
1032
   while ((length - position) > 0)
1033
     {
1034
        if (!memcmp(buf + position, App0, sizeof(App0)))
1035
          {
1036
             res = _get_next_app0(map, length, &position);
1037
             if (!res)
1038
               break;
1039
          }
1040
        else if (!memcmp(buf + position, App1, sizeof(App1)))
1041
          {
1042
             res = _get_orientation_app1(map,
1043
                                         length,
1044
                                         &position,
1045
                                         &orientation,
1046
                                         flipped);
1047
             if (!res)
1048
               break;
1049
             if (orientation != -1)
1050
               return orientation;
1051
          }
1052
        else
1053
          break;
1054
     }
1055
   return 0;
1056
}
1057

1058
static void
1059
_rotate_region(unsigned int *r_x, unsigned int *r_y,
1060
               unsigned int *r_w, unsigned int *r_h,
1061
               unsigned int x, unsigned int y,
1062
               unsigned int w, unsigned int h,
1063
               unsigned int output_w, unsigned int output_h,
1064
               int degree, Eina_Bool flipped)
1065
{
1066
   switch (degree)
1067
     {
1068
      case 90:
1069
        if (flipped)
1070
          {
1071
             *r_x = output_w - (y + h);
1072
             *r_y = output_h - (x + w);
1073
             *r_w = h;
1074
             *r_h = w;
1075
          }
1076
        else
1077
          {
1078
             *r_x = y;
1079
             *r_y = output_h - (x + w);
1080
             *r_w = h;
1081
             *r_h = w;
1082
          }
1083
        break;
1084

1085
      case 180:
1086
        if (flipped)
1087
          {
1088
             *r_y = output_h - (y + h);
1089
          }
1090
        else
1091
          {
1092
             *r_x = output_w - (x + w);
1093
             *r_y = output_h - (y + h);
1094
          }
1095
        break;
1096

1097
      case 270:
1098
        if (flipped)
1099
          {
1100
             *r_x = y;
1101
             *r_y = x;
1102
             *r_w = h;
1103
             *r_h = w;
1104
          }
1105
        else
1106
          {
1107
             *r_x = output_w - (y + h);
1108
             *r_y = x;
1109
             *r_w = h;
1110
             *r_h = w;
1111
          }
1112
        break;
1113

1114
      default:
1115
        if (flipped)
1116
          *r_x = output_w - (x + w);
1117
        break;
1118
     }
1119
}
1120

1121
static void
1122
_rotate_180(uint32_t *data, int w, int h)
1123
{
1124
   uint32_t *p1, *p2;
1125
   uint32_t pt;
1126
   int x;
1127

1128
   p1 = data;
1129
   p2 = data + (h * w) - 1;
1130
   for (x = (w * h) / 2; --x >= 0; )
1131
     {
1132
        pt = *p1;
1133
        *p1 = *p2;
1134
        *p2 = pt;
1135
        p1++;
1136
        p2--;
1137
     }
1138
}
1139

1140
static void
1141
_flip_horizontal(uint32_t *data, int w, int h)
1142
{
1143
   uint32_t *p1, *p2;
1144
   uint32_t pt;
1145
   int x, y;
1146

1147
   for (y = 0; y < h; y++)
1148
     {
1149
        p1 = data + (y * w);
1150
        p2 = data + ((y + 1) * w) - 1;
1151
        for (x = 0; x < (w >> 1); x++)
1152
          {
1153
             pt = *p1;
1154
             *p1 = *p2;
1155
             *p2 = pt;
1156
             p1++;
1157
             p2--;
1158
          }
1159
     }
1160
}
1161

1162
static void
1163
_flip_vertical(uint32_t *data, int w, int h)
1164
{
1165
   uint32_t *p1, *p2;
1166
   uint32_t pt;
1167
   int x, y;
1168

1169
   for (y = 0; y < (h >> 1); y++)
1170
     {
1171
        p1 = data + (y * w);
1172
        p2 = data + ((h - 1 - y) * w);
1173
        for (x = 0; x < w; x++)
1174
          {
1175
             pt = *p1;
1176
             *p1 = *p2;
1177
             *p2 = pt;
1178
             p1++;
1179
             p2++;
1180
          }
1181
     }
1182
}
1183

1184
static void
1185
_rotate_change_wh(uint32_t *to, uint32_t *from, int w, int h, int dx, int dy)
1186
{
1187
   int x, y;
1188

1189
   for (x = h; --x >= 0; )
1190
     {
1191
        for (y = w; --y >= 0; )
1192
          {
1193
             *to = *from;
1194
             from++;
1195
             to += dy;
1196
          }
1197
        to += dx;
1198
     }
1199
}
1200

1201
static void
1202
_rotate8_180(uint8_t *data, int w, int h)
1203
{
1204
   uint8_t *p1, *p2;
1205
   uint8_t pt;
1206
   int x;
1207

1208
   p1 = data;
1209
   p2 = data + (h * w) - 1;
1210
   for (x = (w * h) / 2; --x >= 0; )
1211
     {
1212
        pt = *p1;
1213
        *p1 = *p2;
1214
        *p2 = pt;
1215
        p1++;
1216
        p2--;
1217
     }
1218
}
1219

1220
static void
1221
_flip_horizontal8(uint8_t *data, int w, int h)
1222
{
1223
   uint8_t *p1, *p2;
1224
   uint8_t pt;
1225
   int x, y;
1226

1227
   for (y = 0; y < h; y++)
1228
     {
1229
        p1 = data + (y * w);
1230
        p2 = data + ((y + 1) * w) - 1;
1231
        for (x = 0; x < (w >> 1); x++)
1232
          {
1233
             pt = *p1;
1234
             *p1 = *p2;
1235
             *p2 = pt;
1236
             p1++;
1237
             p2--;
1238
          }
1239
     }
1240
}
1241

1242
static void
1243
_flip_vertical8(uint8_t *data, int w, int h)
1244
{
1245
   uint8_t *p1, *p2;
1246
   uint8_t pt;
1247
   int x, y;
1248

1249
   for (y = 0; y < (h >> 1); y++)
1250
     {
1251
        p1 = data + (y * w);
1252
        p2 = data + ((h - 1 - y) * w);
1253
        for (x = 0; x < w; x++)
1254
          {
1255
             pt = *p1;
1256
             *p1 = *p2;
1257
             *p2 = pt;
1258
             p1++;
1259
             p2++;
1260
          }
1261
     }
1262
}
1263

1264
static void
1265
_rotate_change_wh8(uint8_t *to, uint8_t *from, int w, int h, int dx, int dy)
1266
{
1267
   int x, y;
1268

1269
   for (x = h; --x >= 0; )
1270
     {
1271
        for (y = w; --y >= 0; )
1272
          {
1273
             *to = *from;
1274
             from++;
1275
             to += dy;
1276
          }
1277
        to += dx;
1278
     }
1279
}
1280

1281
static void
1282
_rotate16_180(uint16_t *data, int w, int h)
1283
{
1284
   uint16_t *p1, *p2;
1285
   uint16_t pt;
1286
   int x;
1287

1288
   p1 = data;
1289
   p2 = data + (h * w) - 1;
1290
   for (x = (w * h) / 2; --x >= 0; )
1291
     {
1292
        pt = *p1;
1293
        *p1 = *p2;
1294
        *p2 = pt;
1295
        p1++;
1296
        p2--;
1297
     }
1298
}
1299

1300
static void
1301
_flip_horizontal16(uint16_t *data, int w, int h)
1302
{
1303
   uint16_t *p1, *p2;
1304
   uint16_t pt;
1305
   int x, y;
1306

1307
   for (y = 0; y < h; y++)
1308
     {
1309
        p1 = data + (y * w);
1310
        p2 = data + ((y + 1) * w) - 1;
1311
        for (x = 0; x < (w >> 1); x++)
1312
          {
1313
             pt = *p1;
1314
             *p1 = *p2;
1315
             *p2 = pt;
1316
             p1++;
1317
             p2--;
1318
          }
1319
     }
1320
}
1321

1322
static void
1323
_flip_vertical16(uint16_t *data, int w, int h)
1324
{
1325
   uint16_t *p1, *p2;
1326
   uint16_t pt;
1327
   int x, y;
1328

1329
   for (y = 0; y < (h >> 1); y++)
1330
     {
1331
        p1 = data + (y * w);
1332
        p2 = data + ((h - 1 - y) * w);
1333
        for (x = 0; x < w; x++)
1334
          {
1335
             pt = *p1;
1336
             *p1 = *p2;
1337
             *p2 = pt;
1338
             p1++;
1339
             p2++;
1340
          }
1341
     }
1342
}
1343

1344
static void
1345
_rotate_change_wh16(uint16_t *to, uint16_t *from, int w, int h, int dx, int dy)
1346
{
1347
   int x, y;
1348

1349
   for (x = h; --x >= 0; )
1350
     {
1351
        for (y = w; --y >= 0; )
1352
          {
1353
             *to = *from;
1354
             from++;
1355
             to += dy;
1356
          }
1357
        to += dx;
1358
     }
1359
}
1360

1361
static Eina_Bool
1362
_emile_jpeg_bind(Emile_Image *image EINA_UNUSED,
1363
                 Emile_Image_Load_Opts *opts EINA_UNUSED,
1364
                 Emile_Image_Animated *animated EINA_UNUSED,
1365
                 Emile_Image_Load_Error *error EINA_UNUSED)
1366
{
1367
   return EINA_TRUE;
1368
}
1369

1370
static Eina_Bool
1371
_emile_jpeg_head(Emile_Image *image,
1372
                 Emile_Image_Property *prop,
1373
                 unsigned int property_size,
1374
                 Emile_Image_Load_Error *error)
1375
{
1376
   volatile Emile_Image_Load_Opts *opts = (image->load_opts) ? &image->opts : NULL;
1377
   const unsigned char *m;
1378
   unsigned int scalew, scaleh;
1379
   struct jpeg_decompress_struct cinfo;
1380
   struct _JPEG_error_mgr jerr;
1381
   unsigned int length;
1382

1383
   /* for rotation decoding */
1384
   volatile int degree = 0;
1385
   volatile Eina_Bool change_wh = EINA_FALSE;
1386
   volatile unsigned int load_opts_w = 0, load_opts_h = 0;
1387

1388
   if (sizeof(Emile_Image_Property) != property_size)
1389
     return EINA_FALSE;
1390

1391
   m = _emile_image_file_source_map(image, &length);
1392
   if (!m)
1393
     return EINA_FALSE;
1394

1395
   memset(&cinfo, 0, sizeof(cinfo));
1396
   cinfo.err = jpeg_std_error(&(jerr.pub));
1397
   cinfo.client_data = NULL;
1398
   jerr.pub.error_exit = _emile_image_jpeg_error_exit_cb;
1399
   jerr.pub.emit_message = _emile_image_jpeg_emit_message_cb;
1400
   jerr.pub.output_message = _emile_image_jpeg_output_message_cb;
1401
   if (setjmp(jerr.setjmp_buffer))
1402
     {
1403
        jpeg_destroy_decompress(&cinfo);
1404
        _emile_jpeg_membuf_src_term(&cinfo);
1405
        if (cinfo.saw_JFIF_marker)
1406
          *error = EMILE_IMAGE_LOAD_ERROR_CORRUPT_FILE;
1407
        else
1408
          *error = EMILE_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT;
1409
        return EINA_FALSE;
1410
     }
1411
   jpeg_create_decompress(&cinfo);
1412

1413
   if (_emile_jpeg_membuf_src(&cinfo, m, length))
1414
     {
1415
        jpeg_destroy_decompress(&cinfo);
1416
        _emile_jpeg_membuf_src_term(&cinfo);
1417
        *error = EMILE_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
1418
        return EINA_FALSE;
1419
     }
1420

1421
   jpeg_read_header(&cinfo, TRUE);
1422
   cinfo.do_fancy_upsampling = FALSE;
1423
   cinfo.do_block_smoothing = FALSE;
1424
   cinfo.dct_method = JDCT_ISLOW; /* JDCT_FLOAT JDCT_IFAST(quality loss) */
1425
   cinfo.dither_mode = JDITHER_ORDERED;
1426
   cinfo.buffered_image = TRUE; /* buffered mode in case jpg is progressive */
1427
   jpeg_start_decompress(&cinfo);
1428

1429
   if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
1430
     {
1431
        /* We do handle GRY8 and AGRY88 (with FF for alpha) colorspace as an output for JPEG */
1432
        prop->cspaces = cspaces_gry;
1433
     }
1434

1435
   /* rotation decoding */
1436
   if (opts && opts->orientation)
1437
     {
1438
        degree = _get_orientation(m, length, &prop->flipped);
1439
        if (degree != 0 || prop->flipped)
1440
          {
1441
             opts->degree = degree;
1442
             prop->rotated = EINA_TRUE;
1443

1444
             if (degree == 90 || degree == 270)
1445
               change_wh = EINA_TRUE;
1446
          }
1447
     }
1448

1449
   /* head decoding */
1450
   prop->w = cinfo.output_width;
1451
   prop->h = cinfo.output_height;
1452
   if ((prop->w < 1) ||
1453
       (prop->h < 1) ||
1454
       (prop->w > IMG_MAX_SIZE) ||
1455
       (prop->h > IMG_MAX_SIZE) ||
1456
       (IMG_TOO_BIG(prop->w, prop->h)))
1457
     {
1458
        jpeg_destroy_decompress(&cinfo);
1459
        _emile_jpeg_membuf_src_term(&cinfo);
1460
        if (IMG_TOO_BIG(prop->w, prop->h))
1461
          *error = EMILE_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
1462
        else
1463
          *error = EMILE_IMAGE_LOAD_ERROR_GENERIC;
1464
        return EINA_FALSE;
1465
     }
1466
   if (opts && opts->scale_down_by > 1)
1467
     {
1468
        prop->w /= opts->scale_down_by;
1469
        prop->h /= opts->scale_down_by;
1470
     }
1471
   else if (opts && opts->dpi > 0.0)
1472
     {
1473
        prop->w = (prop->w * opts->dpi) / 90.0;
1474
        prop->h = (prop->h * opts->dpi) / 90.0;
1475
     }
1476
   else if (opts && ((opts->w > 0) && (opts->h > 0)))
1477
     {
1478
        unsigned int w2 = prop->w, h2 = prop->h;
1479
        /* user set load_opts' w,h on the assumption
1480
           that image already rotated according to it's orientation info */
1481
        if (change_wh)
1482
          {
1483
             load_opts_w = opts->w;
1484
             load_opts_h = opts->h;
1485
             opts->w = load_opts_h;
1486
             opts->h = load_opts_w;
1487
          }
1488

1489
        w2 = opts->w;
1490
        h2 = (opts->w * prop->h) / prop->w;
1491
        if (h2 > opts->h)
1492
          {
1493
             unsigned int w3;
1494
             h2 = opts->h;
1495
             w3 = (opts->h * prop->w) / prop->h;
1496
             if (w3 > w2)
1497
               w2 = w3;
1498
          }
1499
        prop->w = w2;
1500
        prop->h = h2;
1501
        if (change_wh)
1502
          {
1503
             opts->w = load_opts_w;
1504
             opts->h = load_opts_h;
1505
          }
1506
     }
1507
   if (prop->w < 1)
1508
     prop->w = 1;
1509
   if (prop->h < 1)
1510
     prop->h = 1;
1511

1512
   if ((prop->w != cinfo.output_width) || (prop->h != cinfo.output_height))
1513
     {
1514
        scalew = cinfo.output_width / prop->w;
1515
        scaleh = cinfo.output_height / prop->h;
1516

1517
        prop->scale = scalew;
1518
        if (scaleh < scalew)
1519
          prop->scale = scaleh;
1520

1521
        if (prop->scale > 8)
1522
          prop->scale = 8;
1523
        else if (prop->scale < 1)
1524
          prop->scale = 1;
1525

1526
        if (prop->scale == 3)
1527
          prop->scale = 2;
1528
        else if (prop->scale == 5)
1529
          prop->scale = 4;
1530
        else if (prop->scale == 6)
1531
          prop->scale = 4;
1532
        else if (prop->scale == 7)
1533
          prop->scale = 4;
1534
     }
1535

1536
   if (prop->scale > 1)
1537
     {
1538
        jpeg_destroy_decompress(&cinfo);
1539
        _emile_jpeg_membuf_src_term(&cinfo);
1540
        jpeg_create_decompress(&cinfo);
1541

1542
        if (_emile_jpeg_membuf_src(&cinfo, m, length))
1543
          {
1544
             jpeg_destroy_decompress(&cinfo);
1545
             _emile_jpeg_membuf_src_term(&cinfo);
1546
             *error = EMILE_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
1547
             return EINA_FALSE;
1548
          }
1549

1550
        jpeg_read_header(&cinfo, TRUE);
1551
        cinfo.do_fancy_upsampling = FALSE;
1552
        cinfo.do_block_smoothing = FALSE;
1553
        cinfo.scale_num = 1;
1554
        cinfo.scale_denom = prop->scale;
1555
        cinfo.buffered_image = TRUE; /* buffered mode in case jpg is progressive */
1556
        jpeg_calc_output_dimensions(&(cinfo));
1557
        jpeg_start_decompress(&cinfo);
1558
     }
1559

1560
   prop->w = cinfo.output_width;
1561
   prop->h = cinfo.output_height;
1562

1563
   /* be nice and clip region to image. if its totally outside, fail load */
1564
   if (opts && ((opts->region.w > 0) && (opts->region.h > 0)))
1565
     {
1566
        unsigned int load_region_x = opts->region.x;
1567
        unsigned int load_region_y = opts->region.y;
1568
        unsigned int load_region_w = opts->region.w;
1569
        unsigned int load_region_h = opts->region.h;
1570
        if (prop->rotated)
1571
          {
1572
             _rotate_region(&load_region_x, &load_region_y,
1573
                            &load_region_w, &load_region_h,
1574
                            opts->region.x, opts->region.y,
1575
                            opts->region.w, opts->region.h,
1576
                            prop->w, prop->h,
1577
                            degree, prop->flipped);
1578
          }
1579
        if (prop->scale > 1)
1580
          {
1581
             load_region_x /= prop->scale;
1582
             load_region_y /= prop->scale;
1583
             load_region_w /= prop->scale;
1584
             load_region_h /= prop->scale;
1585
          }
1586
        RECTS_CLIP_TO_RECT(load_region_x, load_region_y,
1587
                           load_region_w, load_region_h,
1588
                           0, 0, prop->w, prop->h);
1589
        if ((load_region_w == 0) || (load_region_h == 0))
1590
          {
1591
             jpeg_destroy_decompress(&cinfo);
1592
             _emile_jpeg_membuf_src_term(&cinfo);
1593
             *error = EMILE_IMAGE_LOAD_ERROR_GENERIC;
1594
             return EINA_FALSE;
1595
          }
1596
        prop->w = load_region_w;
1597
        prop->h = load_region_h;
1598
     }
1599
   /* end head decoding */
1600

1601
   if (change_wh)
1602
     {
1603
        unsigned int tmp;
1604
        tmp = prop->w;
1605
        prop->w = prop->h;
1606
        prop->h = tmp;
1607
     }
1608
   jpeg_destroy_decompress(&cinfo);
1609
   _emile_jpeg_membuf_src_term(&cinfo);
1610
   *error = EMILE_IMAGE_LOAD_ERROR_NONE;
1611
   return EINA_TRUE;
1612
}
1613

1614
static inline void
1615
_jpeg_convert_copy(volatile uint32_t **dst, uint8_t **src, unsigned int w, Eina_Bool adobe_marker)
1616
{
1617
   uint32_t *ptr2 = (uint32_t*) *dst;
1618
   uint8_t *ptr = *src;
1619
   unsigned int x;
1620

1621
   if (adobe_marker)
1622
     {
1623
        for (x = 0; x < w; x++)
1624
          {
1625
             /* According to libjpeg doc, Photoshop inverse the values of C, M, Y and K, */
1626
             /* that is C is replaces by 255 - C, etc... */
1627
             /* See the comment below for the computation of RGB values from CMYK ones. */
1628
             *ptr2 = (0xff000000) |
1629
               ((ptr[0] * ptr[3] / 255) << 16) |
1630
               ((ptr[1] * ptr[3] / 255) << 8) |
1631
               ((ptr[2] * ptr[3] / 255));
1632
             ptr += 4;
1633
             ptr2++;
1634
          }
1635
     }
1636
   else
1637
     {
1638
        for (x = 0; x < w; x++)
1639
          {
1640
             /* Conversion from CMYK to RGB is done in 2 steps: */
1641
             /* CMYK => CMY => RGB (see http://www.easyrgb.com/index.php?X=MATH) */
1642
             /* after computation, if C, M, Y and K are between 0 and 1, we have: */
1643
             /* R = (1 - C) * (1 - K) * 255 */
1644
             /* G = (1 - M) * (1 - K) * 255 */
1645
             /* B = (1 - Y) * (1 - K) * 255 */
1646
             /* libjpeg stores CMYK values between 0 and 255, */
1647
             /* so we replace C by C * 255 / 255, etc... and we obtain: */
1648
             /* R = (255 - C) * (255 - K) / 255 */
1649
             /* G = (255 - M) * (255 - K) / 255 */
1650
             /* B = (255 - Y) * (255 - K) / 255 */
1651
             /* with C, M, Y and K between 0 and 255. */
1652
             *ptr2 = (0xff000000) |
1653
               (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
1654
               (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
1655
               (((255 - ptr[2]) * (255 - ptr[3]) / 255));
1656
             ptr += 4;
1657
             ptr2++;
1658
          }
1659
     }
1660

1661
   *dst = ptr2;
1662
   *src = ptr;
1663
}
1664

1665
static inline void
1666
_jpeg_gry8_convert_copy(uint8_t **dst, uint8_t **src, unsigned int w)
1667
{
1668
   uint8_t *ptrg = (uint8_t*) *dst;
1669
   uint8_t *ptr = *src;
1670
   unsigned int x;
1671

1672
   for (x = 0; x < w; x++)
1673
     {
1674
        *ptrg = ptr[0];
1675
        ptrg++;
1676
        ptr++;
1677
     }
1678

1679
   *dst = ptrg;
1680
   *src = ptr;
1681
}
1682

1683
static inline void
1684
_jpeg_agry88_convert_copy(uint16_t **dst, uint8_t **src, unsigned int w)
1685
{
1686
   uint16_t *ptrag = (uint16_t*) *dst;
1687
   uint8_t *ptr = *src;
1688
   unsigned int x;
1689

1690
   for (x = 0; x < w; x++)
1691
     {
1692
        *ptrag = 0xFF00 | ptr[0];
1693
        ptrag++;
1694
        ptr++;
1695
     }
1696

1697
   *dst = ptrag;
1698
   *src = ptr;
1699
}
1700

1701
static inline void
1702
_jpeg_argb8888_convert_copy(volatile uint32_t **dst, uint8_t **src, unsigned int w)
1703
{
1704
   uint32_t *ptr2 = (uint32_t*) *dst;
1705
   uint8_t *ptr = *src;
1706
   unsigned int x;
1707

1708
   for (x = 0; x < w; x++)
1709
     {
1710
        *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]);
1711
        ptr2++;
1712
        ptr++;
1713
     }
1714

1715
   *dst = ptr2;
1716
   *src = ptr;
1717
}
1718

1719
static inline void
1720
_jpeg_copy(volatile uint32_t **dst, uint8_t **src, unsigned int w)
1721
{
1722
   uint32_t *ptr2 = (uint32_t*) *dst;
1723
   uint8_t *ptr = *src;
1724
   unsigned int x;
1725

1726
   for (x = 0; x < w; x++)
1727
     {
1728
        *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]);
1729
        ptr += 3;
1730
        ptr2++;
1731
     }
1732

1733
   *dst = ptr2;
1734
   *src = ptr;
1735
}
1736

1737
static Eina_Bool
1738
_emile_jpeg_data(Emile_Image *image,
1739
                 Emile_Image_Property *prop,
1740
                 unsigned int property_size,
1741
                 void *pixels,
1742
                 Emile_Image_Load_Error *error)
1743
{
1744
   /* Handle RGB, ARGB, GRY and AGRY */
1745
   volatile Emile_Image_Load_Opts *opts = (image->load_opts) ? &image->opts : NULL;
1746
   unsigned int w, h;
1747
   struct jpeg_decompress_struct cinfo;
1748
   struct _JPEG_error_mgr jerr;
1749
   const unsigned char *m = NULL;
1750
   uint8_t *ptr, *line[16], *data;
1751
   volatile uint32_t *ptr2 = NULL;
1752
   uint32_t *ptr_rotate = NULL;
1753
   uint16_t *ptrag = NULL, *ptrag2 = NULL, *ptrag_rotate = NULL;
1754
   uint8_t *ptrg = NULL, *ptrg2 = NULL, *ptrg_rotate = NULL;
1755
   unsigned int y, l, i, scans;
1756
   volatile int region = 0;
1757
   /* rotation setting */
1758
   unsigned int ie_w = 0, ie_h = 0;
1759
   struct
1760
   {
1761
      unsigned int x, y, w, h;
1762
   } opts_region = {0, 0, 0, 0};
1763
   volatile int degree = 0;
1764
   volatile Eina_Bool change_wh = EINA_FALSE;
1765
   volatile Eina_Bool line_done = EINA_FALSE;
1766
   volatile Eina_Bool ptrg_free = EINA_FALSE;
1767
   volatile Eina_Bool ptrag_free = EINA_FALSE;
1768
   volatile Eina_Bool r = EINA_FALSE;
1769
   unsigned int length;
1770
   volatile unsigned short count = 0;
1771

1772
   if (sizeof(Emile_Image_Property) != property_size)
1773
     return EINA_FALSE;
1774

1775
   m = _emile_image_file_source_map(image, &length);
1776
   if (!m)
1777
     return EINA_FALSE;
1778

1779
   memset(&cinfo, 0, sizeof(cinfo));
1780
   if (prop->rotated)
1781
     {
1782
        degree = opts ? opts->degree : 0;
1783
        if (degree == 90 || degree == 270)
1784
          change_wh = EINA_TRUE;
1785
     }
1786

1787
   cinfo.err = jpeg_std_error(&(jerr.pub));
1788
   cinfo.client_data = (void *)(intptr_t) 0x1;
1789
   jerr.pub.error_exit = _emile_image_jpeg_error_exit_cb;
1790
   jerr.pub.emit_message = _emile_image_jpeg_emit_message_cb;
1791
   jerr.pub.output_message = _emile_image_jpeg_output_message_cb;
1792
   if (setjmp(jerr.setjmp_buffer))
1793
     {
1794
        *error = EMILE_IMAGE_LOAD_ERROR_CORRUPT_FILE;
1795
        goto on_error;
1796
     }
1797
   jpeg_create_decompress(&cinfo);
1798

1799
   if (_emile_jpeg_membuf_src(&cinfo, m, length))
1800
     {
1801
        *error = EMILE_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
1802
        goto on_error;
1803
     }
1804

1805
   jpeg_read_header(&cinfo, TRUE);
1806
   cinfo.do_fancy_upsampling = FALSE;
1807
   cinfo.do_block_smoothing = FALSE;
1808
   cinfo.dct_method = JDCT_ISLOW; /* JDCT_FLOAT JDCT_IFAST(quality loss) */
1809
   cinfo.dither_mode = JDITHER_ORDERED;
1810

1811
   if (prop->scale > 1)
1812
     {
1813
        cinfo.scale_num = 1;
1814
        cinfo.scale_denom = prop->scale;
1815
     }
1816

1817
   /* Colorspace conversion options */
1818
   /* libjpeg can do the following conversions: */
1819
   /* GRAYSCLAE => RGB YCbCr => RGB and YCCK => CMYK */
1820
   switch (cinfo.jpeg_color_space)
1821
     {
1822
      case JCS_UNKNOWN:
1823
        break;
1824

1825
      case JCS_GRAYSCALE:
1826
        if (prop->cspace == EMILE_COLORSPACE_GRY8 ||
1827
            prop->cspace == EMILE_COLORSPACE_AGRY88)
1828
          {
1829
             cinfo.out_color_space = JCS_GRAYSCALE;
1830
             break;
1831
          }
1832
        /* The caller doesn't handle GRAYSCALE,
1833
         * fallback to RGB.
1834
         */
1835
        EINA_FALLTHROUGH;
1836

1837
      case JCS_RGB:
1838
      case JCS_YCbCr:
1839
        cinfo.out_color_space = JCS_RGB;
1840
        break;
1841

1842
      case JCS_CMYK:
1843
      case JCS_YCCK:
1844
        cinfo.out_color_space = JCS_CMYK;
1845
        break;
1846

1847
      default:
1848
        cinfo.out_color_space = JCS_RGB;
1849
        break;
1850
     }
1851

1852
/* head decoding */
1853
   jpeg_calc_output_dimensions(&(cinfo));
1854
   jpeg_start_decompress(&cinfo);
1855

1856
   w = cinfo.output_width;
1857
   h = cinfo.output_height;
1858

1859
   if (change_wh)
1860
     {
1861
        ie_w = prop->h;
1862
        ie_h = prop->w;
1863
     }
1864
   else
1865
     {
1866
        ie_w = prop->w;
1867
        ie_h = prop->h;
1868
     }
1869

1870
   if (opts && ((opts->region.w > 0) && (opts->region.h > 0)))
1871
     {
1872
        region = 1;
1873

1874
         /* scale value already applied when decompress.
1875
            When access to decoded image, have to apply scale value to region value */
1876
        if (prop->scale > 1)
1877
          {
1878
             opts_region.x = opts->region.x / prop->scale;
1879
             opts_region.y = opts->region.y / prop->scale;
1880
             opts_region.w = opts->region.w / prop->scale;
1881
             opts_region.h = opts->region.h / prop->scale;
1882

1883
          }
1884
        else
1885
          {
1886
             opts_region.x = opts->region.x;
1887
             opts_region.y = opts->region.y;
1888
             opts_region.w = opts->region.w;
1889
             opts_region.h = opts->region.h;
1890
          }
1891

1892

1893
        if (prop->rotated)
1894
          {
1895
             unsigned int load_region_x = 0, load_region_y = 0;
1896
             unsigned int load_region_w = 0, load_region_h = 0;
1897

1898
             load_region_x = opts_region.x;
1899
             load_region_y = opts_region.y;
1900
             load_region_w = opts_region.w;
1901
             load_region_h = opts_region.h;
1902
             _rotate_region(&opts_region.x, &opts_region.y,
1903
                            &opts_region.w, &opts_region.h,
1904
                            load_region_x, load_region_y,
1905
                            load_region_w, load_region_h,
1906
                            w, h, degree, prop->flipped);
1907
          }
1908

1909
     }
1910
   if ((!region) && ((w != ie_w) || (h != ie_h)))
1911
     {
1912
        *error = EMILE_IMAGE_LOAD_ERROR_GENERIC;
1913
        goto on_error;
1914
     }
1915
   if ((region) && ((ie_w != opts_region.w) || (ie_h != opts_region.h)))
1916
     {
1917
        *error = EMILE_IMAGE_LOAD_ERROR_GENERIC;
1918
        goto on_error;
1919
     }
1920

1921
   switch (prop->cspace)
1922
     {
1923
      case EMILE_COLORSPACE_GRY8:
1924
      case EMILE_COLORSPACE_AGRY88:
1925
        if (!(cinfo.out_color_space == JCS_GRAYSCALE &&
1926
              cinfo.output_components == 1))
1927
          {
1928
             *error = EMILE_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT;
1929
             goto on_error;
1930
          }
1931
        break;
1932

1933
      case EMILE_COLORSPACE_ARGB8888:
1934
        if (!((cinfo.out_color_space == JCS_RGB && cinfo.output_components == 3) ||
1935
              (cinfo.out_color_space == JCS_CMYK && cinfo.output_components == 4)))
1936
          {
1937
             *error = EMILE_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT;
1938
             goto on_error;
1939
          }
1940
        break;
1941

1942
      default:
1943
        *error = EMILE_IMAGE_LOAD_ERROR_GENERIC;
1944
        goto on_error;
1945
     }
1946

1947
   /* end head decoding */
1948
   /* data decoding */
1949
   if (cinfo.rec_outbuf_height > 16)
1950
     {
1951
        *error = EMILE_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT;
1952
        goto on_error;
1953
     }
1954
   data = alloca(w * 16 * cinfo.output_components);
1955
   if ((prop->rotated) && change_wh)
1956
     {
1957
        if (prop->cspace == EMILE_COLORSPACE_GRY8)
1958
          {
1959
             ptrg = malloc(w * h * sizeof(uint8_t));
1960
             ptrg_rotate = ptrg;
1961
             ptrg_free = EINA_TRUE;
1962
          }
1963
        else if (prop->cspace == EMILE_COLORSPACE_AGRY88)
1964
          {
1965
             ptrag = malloc(w * h * sizeof(uint16_t));
1966
             ptrag_rotate = ptrag;
1967
             ptrag_free = EINA_TRUE;
1968
          }
1969
        else
1970
          {
1971
             ptr2 = malloc(w * h * sizeof(uint32_t));
1972
             ptr_rotate = (uint32_t*) ptr2;
1973
          }
1974
     }
1975
   else
1976
     {
1977
        ptr2 = pixels;
1978
        ptrag = pixels;
1979
        ptrg = pixels;
1980
     }
1981

1982
   if (!ptr2 && !ptrag && !ptrg)
1983
     {
1984
        *error = EMILE_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
1985
        goto on_error;
1986
     }
1987

1988
   /* We handle first CMYK (4 components) */
1989
   if (cinfo.output_components == 4)
1990
     {
1991
        // FIXME: handle region
1992
        for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
1993
          line[i] = data + (i * w * 4);
1994
        for (l = 0; l < h; l += cinfo.rec_outbuf_height)
1995
          {
1996
             // Check for continuing every 16 scanlines fetch
1997
             EMILE_IMAGE_TASK_CHECK(image, count, 0xF, error, on_error);
1998

1999
             jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
2000
             scans = cinfo.rec_outbuf_height;
2001
             if ((h - l) < scans)
2002
               scans = h - l;
2003
             ptr = data;
2004
             if (!region)
2005
               {
2006
                  for (y = 0; y < scans; y++)
2007
                    {
2008
                       _jpeg_convert_copy(&ptr2, &ptr, w, cinfo.saw_Adobe_marker);
2009
                    }
2010
               }
2011
             else
2012
               {
2013
                  /* if line # > region last line, break */
2014
                  if (l >= (opts_region.y + opts_region.h))
2015
                    {
2016
                       line_done = EINA_TRUE;
2017
                       /* if rotation flag is set , we have to rotate image */
2018
                       goto done;
2019
                       /*jpeg_destroy_decompress(&cinfo);
2020
                          _emile_jpeg_membuf_src_term(&cinfo);
2021
                        * error = EMILE_IMAGE_LOAD_ERROR_NONE;
2022
                          return EINA_FALSE; */
2023
                    }
2024
                  /* else if scan block intersects region start or later */
2025
                  else if ((l + scans) > (opts_region.y))
2026
                    {
2027
                       for (y = 0; y < scans; y++)
2028
                         {
2029
                            if (((y + l) >= opts_region.y) && ((y + l) < (opts_region.y + opts_region.h)))
2030
                              {
2031
                                 ptr += opts_region.x;
2032
                                 _jpeg_convert_copy(&ptr2, &ptr, opts_region.w, cinfo.saw_Adobe_marker);
2033
                                 ptr += (4 * (w - (opts_region.x + opts_region.w)));
2034
                              }
2035
                            else
2036
                              ptr += (4 * w);
2037
                         }
2038
                    }
2039
               }
2040
          }
2041
     }
2042
   /* We handle then RGB with 3 components */
2043
   else if (cinfo.output_components == 3)
2044
     {
2045
/*
2046
        double t;
2047
        if (region)
2048
          {
2049
             // debug for now
2050
             printf("R| %p %5ix%5i %s: %5i %5i %5ix%5i - ",
2051
                    ie,
2052
                    ie->w, ie->h,
2053
                    ie->file,
2054
                    opts_region.x,
2055
                    opts_region.y,
2056
                    opts_region.w,
2057
                    opts_region.h);
2058
          }
2059
        t = get_time();
2060
 */
2061
        for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
2062
          line[i] = data + (i * w * 3);
2063
        for (l = 0; l < h; l += cinfo.rec_outbuf_height)
2064
          {
2065
             // Check for continuing every 16 scanlines fetch
2066
             EMILE_IMAGE_TASK_CHECK(image, count, 0xF, error, on_error);
2067

2068
             jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
2069
             scans = cinfo.rec_outbuf_height;
2070
             if ((h - l) < scans)
2071
               scans = h - l;
2072
             ptr = data;
2073
             if (!region)
2074
               {
2075
                  for (y = 0; y < scans; y++)
2076
                    {
2077
                       _jpeg_copy(&ptr2, &ptr, w);
2078
                    }
2079
               }
2080
             else
2081
               {
2082
                  /* if line # > region last line, break
2083
                     but not return immediately for rotation job */
2084
                  if (l >= (opts_region.y + opts_region.h))
2085
                    {
2086
                       line_done = EINA_TRUE;
2087
                       /* if rotation flag is set , we have to rotate image */
2088
                       goto done;
2089
                    }
2090
                  /* else if scan block intersects region start or later */
2091
                  else if ((l + scans) > (opts_region.y))
2092
                    {
2093
                       for (y = 0; y < scans; y++)
2094
                         {
2095
                            if (((y + l) >= opts_region.y) &&
2096
                                ((y + l) < (opts_region.y + opts_region.h)))
2097
                              {
2098
                                 ptr += (3 * opts_region.x);
2099
                                 _jpeg_copy(&ptr2, &ptr, opts_region.w);
2100
                                 ptr += (3 * (w - (opts_region.x + opts_region.w)));
2101
                              }
2102
                            else
2103
                              ptr += (3 * w);
2104
                         }
2105
                    }
2106
               }
2107
          }
2108
/*
2109
        t = get_time() - t;
2110
        printf("%3.3f\n", t);
2111
 */
2112
     }
2113
   /* We finally handle RGB with 1 component */
2114
   else if (cinfo.output_components == 1)
2115
     {
2116
        ptrg2 = ptrg;
2117
        ptrag2 = ptrag;
2118
        for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
2119
          line[i] = data + (i * w);
2120
        for (l = 0; l < h; l += cinfo.rec_outbuf_height)
2121
          {
2122
             // Check for continuing every 16 scanlines fetch
2123
             EMILE_IMAGE_TASK_CHECK(image, count, 0xF, error, on_error);
2124

2125
             jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
2126
             scans = cinfo.rec_outbuf_height;
2127
             if ((h - l) < scans)
2128
               scans = h - l;
2129
             ptr = data;
2130
             if (!region)
2131
               {
2132
                  for (y = 0; y < scans; y++)
2133
                    {
2134
                       switch (prop->cspace)
2135
                         {
2136
                          case EMILE_COLORSPACE_GRY8:
2137
                             _jpeg_gry8_convert_copy(&ptrg2, &ptr, w);
2138
                             break;
2139
                          case EMILE_COLORSPACE_AGRY88:
2140
                             _jpeg_agry88_convert_copy(&ptrag2, &ptr, w);
2141
                             break;
2142
                          default:
2143
                             _jpeg_argb8888_convert_copy(&ptr2, &ptr, w);
2144
                             break;
2145
                         }
2146
                    }
2147
               }
2148
             else
2149
               {
2150
                  /* if line # > region last line, break */
2151
                  if (l >= (opts_region.y + opts_region.h))
2152
                    {
2153
                       line_done = EINA_TRUE;
2154
                       /* if rotation flag is set , we have to rotate image */
2155
                       goto done;
2156
                       /*jpeg_destroy_decompress(&cinfo);
2157
                          _emile_jpeg_membuf_src_term(&cinfo);
2158
                        * error = EMILE_IMAGE_LOAD_ERROR_NONE;
2159
                          return EINA_TRUE; */
2160
                    }
2161
                  /* else if scan block intersects region start or later */
2162
                  else if ((l + scans) > (opts_region.y))
2163
                    {
2164
                       for (y = 0; y < scans; y++)
2165
                         {
2166
                            if (((y + l) >= opts_region.y) &&
2167
                                ((y + l) < (opts_region.y + opts_region.h)))
2168
                              {
2169
                                 ptr += opts_region.x;
2170
                                 switch (prop->cspace)
2171
                                   {
2172
                                    case EMILE_COLORSPACE_GRY8:
2173
                                       _jpeg_gry8_convert_copy(&ptrg2, &ptr, opts_region.w);
2174
                                       break;
2175
                                    case EMILE_COLORSPACE_AGRY88:
2176
                                       _jpeg_agry88_convert_copy(&ptrag2, &ptr, opts_region.w);
2177
                                       break;
2178
                                    default:
2179
                                       _jpeg_argb8888_convert_copy(&ptr2, &ptr, opts_region.w);
2180
                                       break;
2181
                                   }
2182
                                 ptr += w - (opts_region.x + opts_region.w);
2183
                              }
2184
                            else
2185
                              ptr += w;
2186
                         }
2187
                    }
2188
               }
2189
          }
2190
     }
2191
   /* if rotation operation need, rotate it */
2192
done:
2193

2194
   if (prop->rotated)
2195
     {
2196
        uint32_t *to;
2197
        uint8_t *to8;
2198
        uint16_t *to16;
2199
        int hw;
2200

2201
        hw = ie_w * ie_h;
2202
        to = pixels;
2203
        to8 = pixels;
2204
        to16 = pixels;
2205

2206
        switch (degree)
2207
          {
2208
           case 90:
2209
             if (prop->cspace == EMILE_COLORSPACE_GRY8)
2210
               {
2211
                  if (prop->flipped)
2212
                    _rotate_change_wh8(to8 + hw - 1, ptrg_rotate, ie_w, ie_h, hw - 1, -ie_h);
2213
                  else
2214
                    _rotate_change_wh8(to8 + ie_h - 1, ptrg_rotate, ie_w, ie_h, -hw - 1, ie_h);
2215
               }
2216
             else if (prop->cspace == EMILE_COLORSPACE_AGRY88)
2217
               {
2218
                  if (prop->flipped)
2219
                    _rotate_change_wh16(to16 + hw - 1, ptrag_rotate, ie_w, ie_h, hw - 1, -ie_h);
2220
                  else
2221
                    _rotate_change_wh16(to16 + ie_h - 1, ptrag_rotate, ie_w, ie_h, -hw - 1, ie_h);
2222
               }
2223
             else
2224
               {
2225
                  if (prop->flipped)
2226
                    _rotate_change_wh(to + hw - 1, ptr_rotate, ie_w, ie_h, hw - 1, -ie_h);
2227
                  else
2228
                    _rotate_change_wh(to + ie_h - 1, ptr_rotate, ie_w, ie_h, -hw - 1, ie_h);
2229
               }
2230
             break;
2231

2232
           case 180:
2233
             if (prop->cspace == EMILE_COLORSPACE_GRY8)
2234
               {
2235
                  if (prop->flipped)
2236
                    _flip_vertical8(to8, ie_w, ie_h);
2237
                  else
2238
                    _rotate8_180(to8, ie_w, ie_h);
2239
               }
2240
             else if (prop->cspace == EMILE_COLORSPACE_AGRY88)
2241
               {
2242
                  if (prop->flipped)
2243
                    _flip_vertical16(to16, ie_w, ie_h);
2244
                  else
2245
                    _rotate16_180(to16, ie_w, ie_h);
2246
               }
2247
             else
2248
               {
2249
                  if (prop->flipped)
2250
                    _flip_vertical(to, ie_w, ie_h);
2251
                  else
2252
                    _rotate_180(to, ie_w, ie_h);
2253
               }
2254
             break;
2255

2256
           case 270:
2257
             if (prop->cspace == EMILE_COLORSPACE_GRY8)
2258
               {
2259
                  if (prop->flipped)
2260
                    _rotate_change_wh8(to8, ptrg_rotate, ie_w, ie_h, -hw + 1, ie_h);
2261
                  else
2262
                    _rotate_change_wh8(to8 + hw - ie_h, ptrg_rotate, ie_w, ie_h, hw + 1, -ie_h);
2263
               }
2264
             else if (prop->cspace == EMILE_COLORSPACE_AGRY88)
2265
               {
2266
                  if (prop->flipped)
2267
                    _rotate_change_wh16(to16, ptrag_rotate, w, h, -hw + 1, h);
2268
                  else
2269
                    _rotate_change_wh16(to16 + hw - ie_h, ptrag_rotate, ie_w, ie_h, hw + 1, -ie_h);
2270
               }
2271
             else
2272
               {
2273
                  if (prop->flipped)
2274
                    _rotate_change_wh(to, ptr_rotate, ie_w, ie_h, -hw + 1, ie_h);
2275
                  else
2276
                    _rotate_change_wh(to + hw - ie_h, ptr_rotate, ie_w, ie_h, hw + 1, -ie_h);
2277
               }
2278
             break;
2279

2280
           default:
2281
             if (prop->flipped)
2282
               {
2283
                  if (prop->cspace == EMILE_COLORSPACE_GRY8)
2284
                    _flip_horizontal8(to8, ie_w, ie_h);
2285
                  else if (prop->cspace == EMILE_COLORSPACE_AGRY88)
2286
                    _flip_horizontal16(to16, ie_w, ie_h);
2287
                  else
2288
                    _flip_horizontal(to, ie_w, ie_h);
2289
               }
2290
             break;
2291
          }
2292
        if (ptr_rotate)
2293
          {
2294
             free(ptr_rotate);
2295
             ptr_rotate = NULL;
2296
          }
2297
     }
2298

2299
   if (line_done)
2300
     {
2301
        *error = EMILE_IMAGE_LOAD_ERROR_NONE;
2302
        goto on_error;
2303
     }
2304
   /* end data decoding */
2305
   jpeg_finish_decompress(&cinfo);
2306
   *error = EMILE_IMAGE_LOAD_ERROR_NONE;
2307
   r = EINA_TRUE;
2308

2309
 on_error:
2310
   if (ptrg_free) free(ptrg);
2311
   if (ptrag_free) free(ptrag);
2312

2313
   jpeg_destroy_decompress(&cinfo);
2314
   _emile_jpeg_membuf_src_term(&cinfo);
2315
   _emile_image_file_source_unmap(image);
2316
   return r;
2317

2318
}
2319

2320
static void
2321
_emile_jpeg_close(Emile_Image *image EINA_UNUSED)
2322
{
2323
   /* JPEG file loader doesn't keep any data allocated around (for now) */
2324
}
2325

2326
/* Generic helper to instantiate a new Emile_Image */
2327

2328
static Emile_Image *
2329
_emile_image_new(Eina_Bool (*bind)(Emile_Image *image, Emile_Image_Load_Opts *opts, Emile_Image_Animated *animated, Emile_Image_Load_Error *error),
2330
                 Eina_Bool (*head)(Emile_Image *image, Emile_Image_Property *prop, unsigned int property_size, Emile_Image_Load_Error *error),
2331
                 Eina_Bool (*data)(Emile_Image *image, Emile_Image_Property *prop, unsigned int property_size, void *pixels, Emile_Image_Load_Error *error),
2332
                 void (*close)(Emile_Image *image))
2333
{
2334
   Emile_Image *ei;
2335

2336
   ei = calloc(1, sizeof(Emile_Image));
2337
   if (!ei)
2338
     return NULL;
2339

2340
   ei->bind = bind;
2341
   ei->head = head;
2342
   ei->data = data;
2343
   ei->close = close;
2344

2345
   return ei;
2346
}
2347

2348
static void
2349
_emile_image_binbuf_set(Emile_Image *ei, Eina_Binbuf *source)
2350
{
2351
   ei->source.bin = source;
2352
   ei->bin_source = EINA_TRUE;
2353
}
2354

2355
static void
2356
_emile_image_file_set(Emile_Image *ei, Eina_File *source)
2357
{
2358
   ei->source.f = eina_file_dup(source);
2359
   ei->bin_source = EINA_FALSE;
2360
}
2361

2362
static Emile_Image *
2363
_emile_image_bind(Emile_Image *ei,
2364
                  Emile_Image_Load_Opts *opts,
2365
                  Emile_Image_Animated *animated,
2366
                  Emile_Image_Load_Error *error)
2367
{
2368
   if (opts)
2369
     {
2370
        ei->opts = *opts;
2371
        ei->opts.orientation = !!ei->opts.orientation;
2372
        ei->load_opts = 1;
2373
     }
2374

2375
   *error = EMILE_IMAGE_LOAD_ERROR_NONE;
2376
   if (ei->bind(ei, opts, animated, error))
2377
     return ei;
2378

2379
   /* File is not of that format */
2380
   if (!ei->bin_source)
2381
     eina_file_close(ei->source.f);
2382
   free(ei);
2383
   return NULL;
2384
}
2385

2386
/* Public API to manipulate Emile_Image */
2387

2388
EAPI Emile_Image *
2389
emile_image_tgv_memory_open(Eina_Binbuf *source,
2390
                            Emile_Image_Load_Opts *opts,
2391
                            Emile_Image_Animated *animated,
2392
                            Emile_Image_Load_Error *error)
2393
{
2394
   Emile_Image *ei;
2395

2396
   ei = _emile_image_new(_emile_tgv_bind,
2397
                         _emile_tgv_head,
2398
                         _emile_tgv_data,
2399
                         _emile_tgv_close);
2400
   if (!ei)
2401
     return NULL;
2402

2403
   _emile_image_binbuf_set(ei, source);
2404
   return _emile_image_bind(ei, opts, animated, error);
2405
}
2406

2407
EAPI Emile_Image *
2408
emile_image_tgv_file_open(Eina_File *source,
2409
                          Emile_Image_Load_Opts *opts,
2410
                          Emile_Image_Animated *animated,
2411
                          Emile_Image_Load_Error *error)
2412
{
2413
   Emile_Image *ei;
2414

2415
   ei = _emile_image_new(_emile_tgv_bind,
2416
                         _emile_tgv_head,
2417
                         _emile_tgv_data,
2418
                         _emile_tgv_close);
2419
   if (!ei)
2420
     return NULL;
2421

2422
   _emile_image_file_set(ei, source);
2423
   return _emile_image_bind(ei, opts, animated, error);
2424
}
2425

2426
EAPI Emile_Image *
2427
emile_image_jpeg_memory_open(Eina_Binbuf *source,
2428
                             Emile_Image_Load_Opts *opts,
2429
                             Emile_Image_Animated *animated,
2430
                             Emile_Image_Load_Error *error)
2431
{
2432
   Emile_Image *ei;
2433

2434
   ei = _emile_image_new(_emile_jpeg_bind,
2435
                         _emile_jpeg_head,
2436
                         _emile_jpeg_data,
2437
                         _emile_jpeg_close);
2438
   if (!ei)
2439
     return NULL;
2440

2441
   _emile_image_binbuf_set(ei, source);
2442
   return _emile_image_bind(ei, opts, animated, error);
2443
}
2444

2445
EAPI Emile_Image *
2446
emile_image_jpeg_file_open(Eina_File *source,
2447
                           Emile_Image_Load_Opts *opts,
2448
                           Emile_Image_Animated *animated,
2449
                           Emile_Image_Load_Error *error)
2450
{
2451
   Emile_Image *ei;
2452

2453
   ei = _emile_image_new(_emile_jpeg_bind,
2454
                         _emile_jpeg_head,
2455
                         _emile_jpeg_data,
2456
                         _emile_jpeg_close);
2457
   if (!ei)
2458
     return NULL;
2459

2460
   _emile_image_file_set(ei, source);
2461
   return _emile_image_bind(ei, opts, animated, error);
2462
}
2463

2464
EAPI void
2465
emile_image_callback_set(Emile_Image *image, Emile_Action_Cb callback, Emile_Action action, const void *data)
2466
{
2467
   if (!image) return ;
2468
   // We only handle one type of callback for now
2469
   if (action != EMILE_ACTION_CANCELLED) return ;
2470

2471
   image->cancelled_data = data;
2472
   image->cancelled = callback;
2473
}
2474

2475
EAPI void
2476
emile_image_close(Emile_Image *image)
2477
{
2478
   if (!image)
2479
     return;
2480

2481
   _emile_image_file_source_unmap(image);
2482
   if (!image->bin_source)
2483
     eina_file_close(image->source.f);
2484
   image->close(image);
2485
   free(image);
2486
}
2487

2488
EAPI Eina_Bool
2489
emile_image_head(Emile_Image *image,
2490
                 Emile_Image_Property *prop,
2491
                 unsigned int property_size,
2492
                 Emile_Image_Load_Error *error)
2493
{
2494
   if (!image)
2495
     return EINA_FALSE;
2496

2497
   *error = EMILE_IMAGE_LOAD_ERROR_NONE;
2498
   return image->head(image, prop, property_size, error);
2499
}
2500

2501
EAPI Eina_Bool
2502
emile_image_data(Emile_Image *image,
2503
                 Emile_Image_Property *prop,
2504
                 unsigned int property_size,
2505
                 void *pixels,
2506
                 Emile_Image_Load_Error *error)
2507
{
2508
   if (!image)
2509
     return EINA_FALSE;
2510

2511
   *error = EMILE_IMAGE_LOAD_ERROR_NONE;
2512
   return image->data(image, prop, property_size, pixels, error);
2513
}
2514

2515
EAPI const char *
2516
emile_load_error_str(Emile_Image *source EINA_UNUSED,
2517
                     Emile_Image_Load_Error error)
2518
{
2519
   switch (error)
2520
     {
2521
      case EMILE_IMAGE_LOAD_ERROR_NONE:
2522
        return "No error";
2523

2524
      case EMILE_IMAGE_LOAD_ERROR_GENERIC:
2525
        return "Generic error encountered while loading image.";
2526

2527
      case EMILE_IMAGE_LOAD_ERROR_DOES_NOT_EXIST:
2528
        return "File does not exist.";
2529

2530
      case EMILE_IMAGE_LOAD_ERROR_PERMISSION_DENIED:
2531
        return "Permission to open file denied.";
2532

2533
      case EMILE_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED:
2534
        return "Not enough memory to open file.";
2535

2536
      case EMILE_IMAGE_LOAD_ERROR_CORRUPT_FILE:
2537
        return "File is corrupted.";
2538

2539
      case EMILE_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT:
2540
        return "Unexpected file format.";
2541

2542
      case EMILE_IMAGE_LOAD_ERROR_CANCELLED:
2543
        return "Loading was stopped by an external request.";
2544
     }
2545
   return NULL;
2546
}
2547

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.