aboutsummaryrefslogtreecommitdiffstats
path: root/efl/evas/efl.evas_object_image.pxi
blob: f648922fa442c9c0203d4dbb2eb93b922a4b55ca (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
# Copyright (C) 2007-2013 various contributors (see AUTHORS)
#
# This file is part of Python-EFL.
#
# Python-EFL is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# Python-EFL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this Python-EFL.  If not, see <http://www.gnu.org/licenses/>.

cdef extern from "Python.h":
    PyObject * PyMemoryView_FromBuffer(Py_buffer *info)

from cpython.buffer cimport Py_buffer, PyObject_CheckBuffer, \
    PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE

from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free


cdef int _data_size_get(Evas_Object *obj):
    cdef int stride, h, bpp, cspace, have_alpha
    stride = evas_object_image_stride_get(obj)
    evas_object_image_size_get(obj, NULL, &h)
    cspace = evas_object_image_colorspace_get(obj)
    have_alpha = evas_object_image_alpha_get(obj)
    if cspace == EVAS_COLORSPACE_ARGB8888:
        bpp = 4
    elif cspace == EVAS_COLORSPACE_RGB565_A5P:
        if have_alpha == 0:
            bpp = 2
        else:
            bpp = 3
    else:
        return 0 # XXX not supported.

    return stride * h * bpp


cdef class Image(Object):
    """

    Image from file or buffer.

    .. rubric:: Introduction

    Image will consider the object's :py:attr:`geometry`
    as the area to paint with tiles as described by :py:attr:`fill` and the
    real pixels (image data) will be stored as described by
    :py:attr:`image_size`. This can be tricky to understand at
    first, but gives flexibility to do everything.

    If an image is loaded from file, it will have
    :py:attr:`image_size` set to its original size, unless some
    other size was set with :py:attr:`load_size`, :py:attr:`load_dpi` or
    :py:attr:`load_scale_down`.

    Pixels will be scaled to match size specified by :py:attr:`fill` using
    either sampled or smooth methods, these can be specified with
    :py:attr:`smooth_scale`. The scale will consider borders as specified by
    :py:attr:`border` and :py:attr:`border_center_fill`, while the former
    specify the border dimensions (top and bottom will scale horizontally, while
    right and left will do vertically, corners are kept unscaled), the latter
    says whenever the center of the image will be used (useful to create
    frames).

    Contents will be tiled using :py:attr:`fill` information in order to paint
    :py:attr:`~efl.evas.Object.geometry`, so if you want an image to be drawn
    just once, you should match every :py:attr:`geometry` = **x, y, w, h** by a
    call to :py:attr:`fill` = **0, 0, w, h**. :py:class:`FilledImage` does that
    for you.

    .. rubric:: Pixel data and buffer API

    Images implement the Python Buffer API, so it's possible to use it
    where buffers are expected (ie: file.write()). Available data will
    depend on :py:attr:`alpha`, :py:attr:`colorspace` and
    :py:attr:`image_size`, lines should be considered multiple
    of :py:attr:`stride`, with the following considerations about
    colorspace:

    - **EVAS_COLORSPACE_ARGB8888:** This pixel format is a linear block of
        pixels, starting at the top-left row by row until the bottom right of
        the image or pixel region. All pixels are 32-bit unsigned int's with
        the high-byte being alpha and the low byte being blue in the format
        ARGB. Alpha may or may not be used by evas depending on the alpha flag
        of the image, but if not used, should be set to 0xff anyway.
        This colorspace uses premultiplied alpha. That means that R, G and B
        cannot exceed A in value. The conversion from non-premultiplied
        colorspace is::

            R = (r * a) / 255; G = (g * a) / 255; B = (b * a) / 255;

        So 50% transparent blue will be: 0x80000080. This will not be "dark" -
        just 50% transparent. Values are 0 == black, 255 == solid or full
        red, green or blue.

    .. **EVAS_COLORSPACE_RGB565_A5P:** In the process of being implemented in
        1 engine only. This may change. This is a pointer to image data for
        16-bit half-word pixel data in 16bpp RGB 565 format (5 bits red,
        6 bits green, 5 bits blue), with the high-byte containing red and the
        low byte containing blue, per pixel. This data is packed row by row
        from the top-left to the bottom right. If the image has an alpha
        channel enabled there will be an extra alpha plane **after** the color
        pixel plane. If not, then this data will not exist and should not be
        accessed in any way. This plane is a set of pixels with 1 byte per
        pixel defining the alpha values of all pixels in the image from
        the top-left to the bottom right of the image, row by row. Even though
        the values of the alpha pixels can be 0 to 255, only values 0 through
        to 31 are used, 31 being solid and 0 being transparent.
        RGB values can be 0 to 31 for red and blue and 0 to 63 for green, with 0
        being black and 31 or 63 being full red, green or blue respectively.
        This colorspace is also pre-multiplied like EVAS_COLORSPACE_ARGB8888 so::

            R = (r * a) / 32; G = (g * a) / 32; B = (b * a) / 32;

    .. note:: if an image is resized it will **tile** it's contents respecting
        geometry set by :py:attr:`fill`, so if you want the contents to be
        **scaled** you need to call :py:attr:`fill` with ``x=0, y=0, w=new_width,
        h=new_height``, or you should use :py:class:`FilledImage` instead.

    :param canvas: Evas canvas for this object
    :type canvas: Canvas
    :keyword size: Width and height
    :type size: tuple of ints
    :keyword pos: X and Y
    :type pos: tuple of ints
    :keyword geometry: X, Y, width, height
    :type geometry: tuple of ints
    :keyword color: R, G, B, A
    :type color: tuple of ints
    :keyword name: Object name
    :type name: string
    :keyword file: File name
    :type file: string

    """
    def __init__(self, Canvas canvas not None, file=None, **kwargs):
        self._set_obj(evas_object_image_add(canvas.obj))

        if file is not None:
            if not isinstance(file, (list, tuple)):
                file = (file, None)
            self.file_set(*file)

        self._set_properties_from_keyword_args(kwargs)

    # TODO:
    # def memfile_set(self, data, size=None, format=None, key=None):
    #     """

    #     Sets the data for an image from memory to be loaded

    #     This is the same as evas_object_image_file_set() but the file to be loaded
    #     may exist at an address in memory (the data for the file, not the filename
    #     itself). The ``data`` at the address is copied and stored for future use, so
    #     no ``data`` needs to be kept after this call is made. It will be managed and
    #     freed for you when no longer needed. The ``size`` is limited to 2 gigabytes
    #     in size, and must be greater than 0. A ``None`` ``data`` pointer is also
    #     invalid. Set the filename to ``None`` to reset to empty state and have the
    #     image file data freed from memory using evas_object_image_file_set().

    #     The ``format`` is optional (pass ``None`` if you don't need/use it). It is
    #     used to help Evas guess better which loader to use for the data. It may
    #     simply be the "extension" of the file as it would normally be on disk
    #     such as "jpg" or "png" or "gif" etc.

    #     :param data: The image file data address
    #     :param size: The size of the image file data in bytes
    #     :param format: The format of the file (optional), or ``None`` if not needed
    #     :param key: The image key in file, or ``None``.

    #     """
    #     if isinstance(format, unicode): format = PyUnicode_AsUTF8String(format)
    #     if isinstance(key, unicode): key = PyUnicode_AsUTF8String(key)
    #     evas_object_image_memfile_set(self.obj, data, size,
    #         <char *>format if format is not None else NULL,
    #         <char *>key if key is not None else NULL)

    property file:
        """Set the image to display a file.

        :type: unicode filename or (unicode filename, unicode key)

        :raise EvasLoadError: on load error.

        """
        def __get__(self):
            cdef const_char *file, *key
            evas_object_image_file_get(self.obj, &file, &key)
            return (_ctouni(file), _ctouni(key))

        def __set__(self, value):
            if isinstance(value, str):
                filename, key = value, None
            else:
                filename, key = value
            cdef int err
            if isinstance(filename, unicode): filename = PyUnicode_AsUTF8String(filename)
            if isinstance(key, unicode): key = PyUnicode_AsUTF8String(key)
            evas_object_image_file_set(self.obj,
                <const_char *>filename if filename is not None else NULL,
                <const_char *>key if key is not None else NULL)
            err = evas_object_image_load_error_get(self.obj)
            if err != EVAS_LOAD_ERROR_NONE:
                raise EvasLoadError(err, filename, key)

    def file_set(self, filename, key=None):
        cdef int err
        if isinstance(filename, unicode): filename = PyUnicode_AsUTF8String(filename)
        if isinstance(key, unicode): key = PyUnicode_AsUTF8String(key)
        evas_object_image_file_set(self.obj,
            <const_char *>filename if filename is not None else NULL,
            <const_char *>key if key is not None else NULL)
        err = evas_object_image_load_error_get(self.obj)
        if err != EVAS_LOAD_ERROR_NONE:
            raise EvasLoadError(err, filename, key)

    def file_get(self):
        cdef const_char *file, *key
        evas_object_image_file_get(self.obj, &file, &key)
        return (_ctouni(file), _ctouni(key))

    property border:
        """How much of each border is not to be scaled.

        When rendering, the image may be scaled to fit the size of the
        image object.  This property reflects what area around the border of
        the image is not to be scaled.  This is useful for
        widget theming, where, for example, buttons may be of varying
        sizes, but the border size must remain constant.

        :type: (int **l**, int **r**, int **t**, int **b**)

        """
        def __get__(self):
            cdef int left, right, top, bottom
            evas_object_image_border_get(self.obj, &left, &right, &top, &bottom)
            return (left, right, top, bottom)

        def __set__(self, spec):
            cdef int left, right, top, bottom
            left, right, top, bottom = spec
            evas_object_image_border_set(self.obj, left, right, top, bottom)

    def border_get(self):
        cdef int left, right, top, bottom
        evas_object_image_border_get(self.obj, &left, &right, &top, &bottom)
        return (left, right, top, bottom)

    def border_set(self, int left, int right, int top, int bottom):
        evas_object_image_border_set(self.obj, left, right, top, bottom)

    property border_center_fill:
        """If the center part of an image (not the border) should be drawn

        .. seealso:: :py:attr:`border`

        When rendering, the image may be scaled to fit the size of the
        image object.  This property reflects if the center part of the scaled
        image is to be drawn or left completely blank. Very useful for frames
        and decorations.

        :type: bool

        """
        def __get__(self):
            return bool(evas_object_image_border_center_fill_get(self.obj))

        def __set__(self, int value):
            evas_object_image_border_center_fill_set(self.obj, value)

    def border_center_fill_get(self):
        return bool(evas_object_image_border_center_fill_get(self.obj))

    def border_center_fill_set(self, int value):
        evas_object_image_border_center_fill_set(self.obj, value)

    property filled:
        """Whether the image object's fill property should track the
        object's size.

        If True, then every :py:func:`efl.evas.Object.resize` will
        **automatically** assign a value to :py:attr:`fill`
        with the that new size (and ``0, 0`` as source image's origin),
        so the bound image will fill the whole object's area.

        :type: bool

        .. seealso:: :py:class:`FilledImage`

        """
        def __set__(self, setting):
            evas_object_image_filled_set(self.obj, setting)

        def __get__(self):
            return bool(evas_object_image_filled_get(self.obj))

    def filled_set(self, setting):
        evas_object_image_filled_set(self.obj, setting)

    def filled_get(self):
        return bool(evas_object_image_filled_get(self.obj))

    property border_scale:
        """The scaling factor (multiplier) for the borders of an image
        object.

        Default is **1.0** - i.e. no scaling

        :type: double

        :see: :py:attr:`border`

        """
        def __set__(self, scale):
            evas_object_image_border_scale_set(self.obj, scale)

        def __get__(self):
            return evas_object_image_border_scale_get(self.obj)

    def border_scale_set(self, scale):
        evas_object_image_border_scale_set(self.obj, scale)

    def border_scale_get(self):
        return evas_object_image_border_scale_get(self.obj)

    property fill:
        """The rectangle that the image will be drawn to.

        Note that the image will be **tiled** around this one rectangle.
        To have only one copy of the image drawn, **x** and **y** must be
        0 and **w** and **h** need to be the width and height of the object
        respectively.

        The default values for the fill parameters is **x** = 0, **y** = 0,
        **w** = 1 and **h** = 1.

        :type: (int **x**, int **y**, int **w**, int **h**)

        """
        def __get__(self):
            cdef int x, y, w, h
            evas_object_image_fill_get(self.obj, &x, &y, &w, &h)
            return (x, y, w, h)

        def __set__(self, spec):
            cdef int x, y, w, h
            x, y, w, h = spec
            evas_object_image_fill_set(self.obj, x, y, w, h)

    def fill_get(self):
        cdef int x, y, w, h
        evas_object_image_fill_get(self.obj, &x, &y, &w, &h)
        return (x, y, w, h)

    def fill_set(self, int x, int y, int w, int h):
        evas_object_image_fill_set(self.obj, x, y, w, h)

    property fill_spread:
        """The tiling mode for the given evas image object's fill.

        One of EVAS_TEXTURE_REFLECT, EVAS_TEXTURE_REPEAT,
        EVAS_TEXTURE_RESTRICT, or EVAS_TEXTURE_PAD.

        :type: Evas_Fill_Spread

        """
        def __set__(self, Evas_Fill_Spread spread):
            evas_object_image_fill_spread_set(self.obj, spread)

        def __get__(self):
            return self.fill_spread_get()

    def fill_spread_set(self, Evas_Fill_Spread spread):
        evas_object_image_fill_spread_set(self.obj, spread)

    def fill_spread_get(self):
        return evas_object_image_fill_spread_get(self.obj)

    property image_size:
        """The size of the image to be displayed.

        Assigning to this property will scale down or crop the image so that it
        is treated as if it were at the given size.
        If the size given is smaller than the image, it will be cropped.
        If the size given is larger, then the image will be treated as if it
        were in the upper left hand corner of a larger image that is
        otherwise transparent.

        This will force pixels to be allocated if they weren't, so
        you should use this before accessing the image as a buffer in order
        to allocate the pixels.

        This will recalculate :py:attr:`stride` based on
        width and the colorspace.

        :type: (int **w**, int **h**)

        """
        def __get__(self):
            cdef int w, h
            evas_object_image_size_get(self.obj, &w, &h)
            return (w, h)

        def __set__(self, spec):
            cdef int w, h
            w, h = spec
            evas_object_image_size_set(self.obj, w, h)

    def image_size_get(self):
        cdef int w, h
        evas_object_image_size_get(self.obj, &w, &h)
        return (w, h)

    def image_size_set(self, int w, int h):
        evas_object_image_size_set(self.obj, w, h)

    property stride:
        """Get the row stride (in pixels) being used to draw this image.

        While image have logical dimension of width and height set by
        :py:attr:`image_size`, the line can be a bit larger than width to
        improve memory alignment.

        The amount of bytes will change based on colorspace, while using
        ARGB8888 it will be multiple of 4 bytes, with colors being laid
        out interleaved, RGB565_A5P will have the first part being RGB
        data using stride in multiple of 2 bytes and after that an
        alpha plane with data using stride in multiple of 1 byte.

        .. note:: This value can change after setting :py:attr:`image_size`.
        .. note:: Unit is pixels, not bytes.

        :type: int

        """
        def __get__(self):
            return evas_object_image_stride_get(self.obj)

    def stride_get(self):
        return evas_object_image_stride_get(self.obj)

    property load_error:
        """The load error.

        :type: int

        """
        def __get__(self):
            return evas_object_image_load_error_get(self.obj)

    def load_error_get(self):
        return evas_object_image_load_error_get(self.obj)

    def image_data_set(self, buf):
        """Sets the raw image data.

        The given buffer will be **copied**, so it's safe to give it a
        temporary object.

        .. note:: that the raw data must be of the same size and colorspace
            of the image. If data is None the current image data will be freed.

        :param buf: The buffer
        :type buf: data

        """
        cdef:
            Py_ssize_t expected_size
            Py_buffer view

        if buf is None:
            evas_object_image_data_set(self.obj, NULL)
            return

        if not PyObject_CheckBuffer(buf):
            raise TypeError("The provided object does not support buffer interface.")

        PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE)

        expected_size = _data_size_get(self.obj)
        if view.itemsize < expected_size:
            raise ValueError(
                "buffer size (%d) is smaller than expected (%d)!" % (
                    view.itemsize, expected_size
                    )
                )

        evas_object_image_data_set(self.obj, <void *>view.buf)

        PyBuffer_Release(&view)

    def image_data_memoryview_get(self, bint for_writing=False, bint simple=True):
        """image_data_memoryview_get(bool for_writing) -> MemoryView

        Get a MemoryView object to the raw image data of the given image object.

        :param bool for_writing: Whether the data being retrieved will be
                modified or not.
        :param bool simple: Whether the MemoryView is 1D or 2D
        :return MemoryView: The raw image data.

        This method returns a MemoryView object to an image object's internal pixel
        buffer, for reading only or read/write. If you request it for
        writing, the image will be marked dirty so that it gets redrawn at
        the next update.

        Each time you call this method on an image object, its data
        buffer will have an internal reference counter
        incremented. Decrement it back by using
        :py:func:`image_data_set`.

        This is best suited for when you want to modify an existing image,
        without changing its dimensions.

        .. note::
            The contents' format returned by it depend on the color
            space of the given image object.

        .. note::
            You may want to use :py:func:`image_data_update_add` to
            inform data changes, if you did any.

        """
        cdef int stride, h, bpp, cspace, have_alpha, img_size

        stride = evas_object_image_stride_get(self.obj)
        evas_object_image_size_get(self.obj, NULL, &h)
        cspace = evas_object_image_colorspace_get(self.obj)
        have_alpha = evas_object_image_alpha_get(self.obj)

        bpp = 0
        if cspace == EVAS_COLORSPACE_ARGB8888:
            bpp = 4
            format = "L"
        elif cspace == EVAS_COLORSPACE_RGB565_A5P:
            if have_alpha == 0:
                bpp = 2
                format = "H"
            else:
                pass #bpp = 3
                # XXX: There's no type that has three bytes.
                #      Is the format string actually used?
        if bpp == 0:
            raise ValueError("Unsupported colorspace")

        img_size = stride * h * bpp

        cdef Py_buffer *img_buf = <Py_buffer *>PyMem_Malloc(sizeof(Py_buffer))
        if img_buf == NULL:
            raise MemoryError

        cdef:
            Py_ssize_t simple_shape[1]
            Py_ssize_t shape[2]
            Py_ssize_t strides[2]
            Py_ssize_t suboffsets[2]

        if simple:
            simple_shape[0] = img_size
        else:
            shape[0] = stride / bpp
            shape[1] = h
            strides[0] = stride
            strides[1] = h * bpp
            suboffsets[0] = -1
            suboffsets[1] = -1

        img_buf.buf = evas_object_image_data_get(self.obj, for_writing)
        img_buf.len = img_size
        img_buf.readonly = not for_writing
        img_buf.format = format
        if simple:
            img_buf.ndim = 1
            img_buf.shape = simple_shape
            img_buf.strides = NULL
            img_buf.suboffsets = NULL
        else:
            img_buf.ndim = 2
            img_buf.shape = shape
            img_buf.strides = strides
            img_buf.suboffsets = suboffsets
        img_buf.itemsize = bpp

        return <object>PyMemoryView_FromBuffer(img_buf)


    # TODO:
    # def image_data_convert(self, to_cspace):
    #     """Converts the raw image data of the given image object to the
    #     specified colorspace.

    #     Note that this function does not modify the raw image data.  If the
    #     requested colorspace is the same as the image colorspace nothing is
    #     done and ``NULL`` is returned. You should use
    #     evas_object_image_colorspace_get() to check the current image
    #     colorspace.

    #     See @ref evas_object_image_colorspace_get.

    #     :param obj: The given image object.
    #     :param to_cspace: The colorspace to which the image raw data will be converted.
    #     :return: A newly allocated data in the format specified by to_cspace.

    #     """
    #     void *evas_object_image_data_convert(self.obj, Evas_Colorspace to_cspace) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);

    # TODO:
    # def image_data_copy_set(self, data):
    #     """Replaces the raw image data of the given image object.

    #     :param data: The raw data to replace.

    #     This function lets the application replace an image objects
    #     internal pixel buffer with an user-allocated one. For best results,
    #     you should generally first call evas_object_image_size_set() with
    #     the width and height for the new buffer.

    #     This call is best suited for when you will be using image data with
    #     different dimensions than the existing image data, if any. If you
    #     only need to modify the existing image in some fashion, then using
    #     evas_object_image_data_get() is probably what you are after.

    #     Note that the caller is responsible for freeing the buffer when
    #     finished with it, as user-set image data will not be automatically
    #     freed when the image object is deleted.

    #     :see: :py:func:`image_data_get` for more details.

    #     """
    #     evas_object_image_data_copy_set(self.obj, void *data)

    def image_data_update_add(self, x, y, w, h):
        """image_data_update_add(int x, int y, int w, int h)

        Mark a sub-region of the image to be redrawn.

        This function schedules a particular rectangular region
        to be updated (redrawn) at the next render.

        :param x: X coordinate
        :type x: int
        :param y: Y coordinate
        :type y: int
        :param w: Width
        :type w: int
        :param h: Height
        :type h: int

        """
        evas_object_image_data_update_add(self.obj, x, y, w, h)

    property alpha:
        """Enable or disable alpha channel.

        :type: bool

        """
        def __get__(self):
            return bool(evas_object_image_alpha_get(self.obj))

        def __set__(self, int value):
            evas_object_image_alpha_set(self.obj, value)

    def alpha_get(self):
        return bool(evas_object_image_alpha_get(self.obj))

    def alpha_set(self, value):
        evas_object_image_alpha_set(self.obj, value)

    property smooth_scale:
        """Enable or disable smooth scaling.

        :type: bool

        """
        def __get__(self):
            return bool(evas_object_image_smooth_scale_get(self.obj))

        def __set__(self, int value):
            evas_object_image_smooth_scale_set(self.obj, value)

    def smooth_scale_get(self):
        return bool(evas_object_image_smooth_scale_get(self.obj))

    def smooth_scale_set(self, value):
        evas_object_image_smooth_scale_set(self.obj, value)

    def preload(self, int cancel=0):
        """preload(bool cancel=False)

        Preload image data asynchronously.

        This will request Evas to create a thread to load image data
        from file, decompress and convert to pre-multiplied format
        used internally.

        This will emit EVAS_CALLBACK_IMAGE_PRELOADED event callback
        when it is done, see on_image_preloaded_add().

        If one calls this function with cancel=True, then preload will
        be canceled and load will happen when image is made visible.

        If image is required before preload is done (ie: pixels are
        retrieved by user or when drawing), then it will be
        automatically canceled and load will be synchronous.

        :param cancel: if True, will cancel preload request.
        :type cancel: bool

        .. seealso: :py:func:`on_image_preloaded_add`

        """
        evas_object_image_preload(self.obj, cancel)


    def reload(self):
        """Force reload of image data."""
        evas_object_image_reload(self.obj)

    def save(self, filename, key=None, flags=None):
        """save(unicode filename, unicode key=None, unicode flags=None)

        Save image to file.

        :param filename: where to save.
        :type filename: unicode
        :param key: some formats may require a key, EET for example.
        :type key: unicode
        :param flags: string of extra flags (separated by space), like
            "quality=85 compress=9".
        :type flags: unicode

        """
        if isinstance(filename, unicode): filename = PyUnicode_AsUTF8String(filename)
        if isinstance(key, unicode): key = PyUnicode_AsUTF8String(key)
        if isinstance(flags, unicode): flags = PyUnicode_AsUTF8String(flags)
        evas_object_image_save(self.obj, filename,
            <const_char *>key if key is not None else NULL,
            <const_char *>flags if flags is not None else NULL)

    # TODO:
    # def image_pixels_import(self, pixels):
    #     """Import pixels from given source to a given canvas image object.

    #     :param pixels: The pixel source to be imported.
    #     :type pixels: Evas_Pixel_Import_Source *
    #     :return: Whether the import was succesful
    #     :rtype: bool

    #     This function imports pixels from a given source to a given canvas image.

    #     """
    #     if not evas_object_image_pixels_import(self.obj, pixels):
    #         raise RuntimeError("Could not import pixels.")

    # TODO:
    # def pixels_get_callback_set(self, func, data):
    #     """Set the callback function to get pixels from a canvas' image.

    #     :param func: The callback function.
    #     :type func: Evas_Object_Image_Pixels_Get_Cb
    #     :param data: The data pointer to be passed to @a func.

    #     This functions sets a function to be the callback function that get
    #     pixes from a image of the canvas.

    #     """
    #     evas_object_image_pixels_get_callback_set(self.obj, func, data)

    property pixels_dirty:
        """Mark or unmark pixels as dirty.

        :type: bool

        """
        def __get__(self):
            return bool(evas_object_image_pixels_dirty_get(self.obj))

        def __set__(self, int value):
            evas_object_image_pixels_dirty_set(self.obj, value)

    def pixels_dirty_get(self):
        return bool(evas_object_image_pixels_dirty_get(self.obj))

    def pixels_dirty_set(self, value):
        evas_object_image_pixels_dirty_set(self.obj, value)

    property load_dpi:
        """Dots-per-inch to be used at image load time.

        :type: double

        """
        def __get__(self):
            return evas_object_image_load_dpi_get(self.obj)

        def __set__(self, int value):
            evas_object_image_load_dpi_set(self.obj, value)

    def load_dpi_get(self):
        return evas_object_image_load_dpi_get(self.obj)

    def load_dpi_set(self, double value):
        evas_object_image_load_dpi_set(self.obj, value)

    property load_size:
        """The size you want image loaded.

        Loads image to the desired size, saving memory when loading large
        files.

        :type: (int **w**, int **h**)

        """
        def __get__(self):
            cdef int w, h
            evas_object_image_load_size_get(self.obj, &w, &h)
            return (w, h)

        def __set__(self, spec):
            cdef int w, h
            w, h = spec
            evas_object_image_load_size_set(self.obj, w, h)

    def load_size_get(self):
        cdef int w, h
        evas_object_image_load_size_get(self.obj, &w, &h)
        return (w, h)

    def load_size_set(self, int w, int h):
        evas_object_image_load_size_set(self.obj, w, h)

    property load_scale_down:
        """Scale down loaded image by the given amount.

        :type: int

        """
        def __get__(self):
            return evas_object_image_load_scale_down_get(self.obj)

        def __set__(self, int value):
            evas_object_image_load_scale_down_set(self.obj, value)

    def load_scale_down_get(self):
        return evas_object_image_load_scale_down_get(self.obj)

    def load_scale_down_set(self, int value):
        evas_object_image_load_scale_down_set(self.obj, value)

    property load_region:
        """Inform a given image object to load a selective region of its
        source image.

        :type: (int **x**, int **y**, int **w**, int **h**)

        This is useful when one is not showing all of an image's
        area on its image object.

        .. note::

            The image loader for the image format in question has to
            support selective region loading in order to this function to take
            effect.

        """
        def __set__(self, value):
            cdef int x, y, w, h
            x, y, w, h = value
            evas_object_image_load_region_set(self.obj, x, y, w, h)

        def __get__(self):
            cdef int x, y, w, h
            evas_object_image_load_region_get(self.obj, &x, &y, &w, &h)
            return x, y, w, h

    def load_region_set(self, int x, int y, int w, int h):
        evas_object_image_load_region_set(self.obj, x, y, w, h)

    def load_region_get(self):
        cdef int x, y, w, h
        evas_object_image_load_region_get(self.obj, &x, &y, &w, &h)
        return x, y, w, h

    property load_orientation:
        """Define if the orientation information in the image file should be honored.

        :type: bool

        """
        def __set__(self, bint enable):
            evas_object_image_load_orientation_set(self.obj, enable)

        def __get__(self):
            return bool(evas_object_image_load_orientation_get(self.obj))

    def load_orientation_set(self, bint enable):
        evas_object_image_load_orientation_set(self.obj, enable)

    def load_orientation_get(self):
        return bool(evas_object_image_load_orientation_get(self.obj))

    property colorspace:
        """The colorspace of image data (pixels).

        May be one of (subject to engine implementation):

        - **EVAS_COLORSPACE_ARGB8888** ARGB 32 bits per pixel, high-byte is
            Alpha, accessed 1 32bit word at a time.

        .. **EVAS_COLORSPACE_YCBCR422P601_PL** YCbCr 4:2:2 Planar, ITU.BT-601
            specifications. The data poitned to is just an array of row
            pointer, pointing to the Y rows, then the Cb, then Cr rows.

        .. **EVAS_COLORSPACE_YCBCR422P709_PL** YCbCr 4:2:2 Planar, ITU.BT-709
            specifications. The data poitned to is just an array of row
            pointer, pointing to the Y rows, then the Cb, then Cr rows.

        .. **EVAS_COLORSPACE_RGB565_A5P** 16bit rgb565 + Alpha plane at end -
            5 bits of the 8 being used per alpha byte.

        :type: Evas_Colorspace

        """
        def __get__(self):
            return evas_object_image_colorspace_get(self.obj)

        def __set__(self, int value):
            evas_object_image_colorspace_set(self.obj, <Evas_Colorspace>value)

    def colorspace_get(self):
        return evas_object_image_colorspace_get(self.obj)

    def colorspace_set(self, int value):
        evas_object_image_colorspace_set(self.obj, <Evas_Colorspace>value)

    property region_support:
        """Region support state

        :type: bool

        """
        def __get__(self):
            return bool(evas_object_image_region_support_get(self.obj))

    def region_support_get(self):
        return bool(evas_object_image_region_support_get(self.obj))

    # TODO: Pass these out as capsules? Find out where they can be used and how
    # property native_surface:
    #     """The native surface of a given image of the canvas

    #     :param surf: The new native surface.

    #     """
    #     def __set__(self, value):
    #         self.native_surface_set(value)

    #     def __get__(self):
    #         return self.native_surface_get()

    # cpdef native_surface_set(self, surf):
    #     evas_object_image_native_surface_set(self.obj, Evas_Native_Surface *surf)

    # cpdef native_surface_get(self):
    #     EAPI Evas_Native_Surface          *evas_object_image_native_surface_get(const Evas_Object *obj) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);

    # property video_surface:
    #     """The video surface linked to a given image of the canvas

    #     :param surf: The new video surface.

    #     """
    #     def __set__(self, value):
    #         self.video_surface_set(value)

    #     def __get__(self):
    #         return self.video_surface_get()

    # cpdef video_surface_set(self, surf):
    #     evas_object_image_video_surface_set(self.obj, Evas_Video_Surface *surf)

    # cpdef video_surface_get(self):
    #     Evas_Video_Surface *evas_object_image_video_surface_get(self.obj)

    property scale_hint:

        """The scale hint value of the image object in the canvas,
        which will affect how Evas is to cache scaled versions of its
        original source image.

        :type: Evas_Image_Scale_Hint


        """
        def __set__(self, Evas_Image_Scale_Hint hint):
            evas_object_image_scale_hint_set(self.obj, hint)

        def __get__(self):
            return self.scale_hint_get()

    def scale_hint_set(self, Evas_Image_Scale_Hint hint):
        evas_object_image_scale_hint_set(self.obj, hint)

    def scale_hint_get(self):
        return evas_object_image_scale_hint_get(self.obj)

    property content_hint:
        """The content hint value of the given image of the canvas.

        For example, if you're on the GL engine and your driver implementation
        supports it, setting this hint to ``EVAS_IMAGE_CONTENT_HINT_DYNAMIC`` will
        make it need **zero** copies at texture upload time, which is an "expensive"
        operation.

        :type: Evas_Image_Content_Hint

        """
        def __set__(self, Evas_Image_Content_Hint hint):
            evas_object_image_content_hint_set(self.obj, hint)

        def __get__(self):
            return evas_object_image_content_hint_get(self.obj)

    def content_hint_set(self, Evas_Image_Content_Hint hint):
        evas_object_image_content_hint_set(self.obj, hint)

    def content_hint_get(self):
        return evas_object_image_content_hint_get(self.obj)

    property alpha_mask:
        """Enable an image to be used as an alpha mask.

        This will set any flags, and discard any excess image data not used as an
        alpha mask.

        .. note::

            There is little point in using a image as alpha mask unless it has
            an alpha channel.

        :type: bool

        """
        def __set__(self, bint ismask):
            evas_object_image_alpha_mask_set(self.obj, ismask)

    def alpha_mask_set(self, bint ismask):
        evas_object_image_alpha_mask_set(self.obj, ismask)

    property source:
        """The source object on an image object to used as a **proxy**.

        If an image object is set to behave as a **proxy**, it will mirror
        the rendering contents of a given **source** object in its drawing
        region, without affecting that source in any way. The source must
        be another valid Evas object. Other effects may be applied to the
        proxy, such as a map (see evas_object_map_set()) to create a
        reflection of the original object (for example).

        Any existing source object on ``obj`` will be removed after this
        call. Setting ``src`` to ``NULL`` clears the proxy object (not in
        "proxy state" anymore).

        :type: Object
        :raise RuntimeError: if source could not be (un)set.

        .. warning:: You cannot set a proxy as another proxy's source.

        .. seealso:: :py:attr:`source_visible`

        """
        def __set__(self, Object src):
            if not evas_object_image_source_set(self.obj, src.obj):
                raise RuntimeError("Could not set image source.")

        def __get__(self):
            return object_from_instance(evas_object_image_source_get(self.obj))

        def __del__(self):
            if not evas_object_image_source_unset(self.obj):
                raise RuntimeError("Could not unset image source.")

    def source_set(self, Object src):
        if not evas_object_image_source_set(self.obj, src.obj):
            raise RuntimeError("Could not set image source.")

    def source_get(self):
        return object_from_instance(evas_object_image_source_get(self.obj))

    def source_unset(self):
        if not evas_object_image_source_unset(self.obj):
            raise RuntimeError("Could not unset image source.")

    property source_visible:
        """Whether the source object is visible or not.

        If set to False, the source object of the proxy will be invisible.

        This API works differently to :py:func:`~efl.evas.Object.show` and
        :py:func:`~efl.evas.Object.hide`. Once source object is hidden by
        :py:func:`~efl.evas.Object.hide` then the proxy object will be hidden as
        well. Actually in this case both objects are excluded from the Evas
        internal update circle.

        By this API, instead, one can toggle the visibility of a proxy's source
        object remaining the proxy visibility untouched.

        :type: bool

        .. warning::

            If the all of proxies are deleted, then the source visibility of the
            source object will be cancelled.

        .. seealso:: :py:attr:`source`

        .. versionadded:: 1.8

        """
        def __set__(self, bint visible):
            evas_object_image_source_visible_set(self.obj, visible)

        def __get__(self):
            return bool(evas_object_image_source_visible_get(self.obj))

    def source_visible_set(self, bint visible):
        evas_object_image_source_visible_set(self.obj, visible)

    def source_visible_get(self):
        return bool(evas_object_image_source_visible_get(self.obj))

    property source_events:
        """Whether an Evas object is to repeat events to source.

        If True, it will make events on the object to also be repeated for the
        source object. When the object and source geometries are different, the
        event position will be transformed to the source object's space.

        If False, events occurring on the object will be processed only on it.

        :type: bool

        .. seealso::

            :py:attr:`source`
            :py:attr:`source_visible`

        .. versionadded:: 1.8

        """
        def __set__(self, bint source):
            evas_object_image_source_events_set(self.obj, source)

        def __get__(self):
            return bool(evas_object_image_source_events_get(self.obj))

    def source_events_set(self, bint source):
        evas_object_image_source_events_set(self.obj, source)

    def source_events_get(self):
        return bool(evas_object_image_source_events_get(self.obj))

    property animated:
        """Check if an image object can be animated (have multiple frames)

        :type: bool

        This returns if the image file of an image object is capable of animation
        such as an animated gif file might. This is only useful to be called once
        the image object file has been set.

        Example::

            obj = Image(mycanvas, file="my_animated_file.gif")

            if obj.animated:
                print("This image has %d frames" % (obj.animated_frame_count,))
                print("Frame 1's duration is %f. You had better set object's frame to 2 after this duration using timer." % (obj.animated_frame_duration_get(1, 0)))
                print("Loop count is %d. You had better run loop %d times." % (obj.loop_count, obj.loop_count))

                loop_type = obj.animated_loop_type
                if loop_type == EVAS_IMAGE_ANIMATED_HINT_LOOP:
                    print("You had better set frame like 1->2->3->1->2->3...")
                elif loop_type == EVAS_IMAGE_ANIMATED_HINT_PINGPONG:
                    print("You had better set frame like 1->2->3->2->1->2...")
                else:
                    print("Unknown loop type.")

                obj.animated_frame = 1
                print("You set image objects frame to 1. You can see frame 1.")

        """
        def __get__(self):
            return bool(evas_object_image_animated_get(self.obj))

    def animated_get(self):
        return bool(evas_object_image_animated_get(self.obj))

    property animated_frame_count:
        """Get the total number of frames of the image object.

        :type: int

        This returns total number of frames the image object supports (if animated)

        """
        def __get__(self):
            return evas_object_image_animated_frame_count_get(self.obj)

    def animated_frame_count_get(self):
        return evas_object_image_animated_frame_count_get(self.obj)

    property animated_loop_type:
        """Get the kind of looping the image object does.

        :type: Evas_Image_Animated_Loop_Hint

        This returns the kind of looping the image object wants to do.

        If it returns EVAS_IMAGE_ANIMATED_HINT_LOOP, you should display frames in a sequence like:
        1->2->3->1->2->3->1...
        If it returns EVAS_IMAGE_ANIMATED_HINT_PINGPONG, it is better to
        display frames in a sequence like: 1->2->3->2->1->2->3->1...

        The default type is EVAS_IMAGE_ANIMATED_HINT_LOOP.

        """
        def __get__(self):
            return evas_object_image_animated_loop_type_get(self.obj)

    def animated_loop_type_get(self):
        return evas_object_image_animated_loop_type_get(self.obj)

    property animated_loop_count:
        """Get the number times the animation of the object loops.

        :type: int

        This returns loop count of image. The loop count is the number of times
        the animation will play fully from first to last frame until the animation
        should stop (at the final frame).

        If 0 is returned, then looping should happen indefinitely (no limit to
        the number of times it loops).

        """
        def __get__(self):
            return evas_object_image_animated_loop_count_get(self.obj)

    def animated_loop_count_get(self):
        return evas_object_image_animated_loop_count_get(self.obj)

    def animated_frame_duration_get(self, int start_frame, int fram_num):
        """animated_frame_duration_get(int start_frame, int fram_num) -> double

        Get the duration of a sequence of frames.

        :param start_frame: The first frame
        :type start_frame: int
        :param fram_num: Number of frames in the sequence
        :type fram_num: int

        :return: The duration of a sequence of frames.
        :rtype: double

        This returns total duration that the specified sequence of frames should
        take in seconds.

        If you set start_frame to 1 and frame_num 0, you get frame 1's duration
        If you set start_frame to 1 and frame_num 1, you get frame 1's duration +
        frame2's duration

        """
        return evas_object_image_animated_frame_duration_get(self.obj, start_frame, fram_num)

    property animated_frame:
        """Set the frame to current frame of an image object

        :type: int

        This set image object's current frame to frame_num with 1 being the first
        frame.

        """
        def __set__(self, int frame_num):
            evas_object_image_animated_frame_set(self.obj, frame_num)

    def animated_frame_set(self, int frame_num):
        evas_object_image_animated_frame_set(self.obj, frame_num)


    def __getbuffer__(self, Py_buffer *view, int flags):
        view.buf = evas_object_image_data_get(self.obj, not view.readonly)
        if view.buf == NULL:
            raise SystemError("image has no allocated buffer.")
        view.len = _data_size_get(self.obj)
        view.format = "L"
        view.ndim = 1
        view.itemsize = 4
        # TODO: Check flags, provide multidim if possible, handle other
        #       colorspaces

    def __releasebuffer__(self, Py_buffer *view):
        evas_object_image_data_set(self.obj, view.buf)
        # TODO: Free possibly allocated memory here (shape, strides, suboffsets)


    def on_image_preloaded_add(self, func, *a, **k):
        """Same as event_callback_add(EVAS_CALLBACK_IMAGE_PRELOADED, ...)"""
        self.event_callback_add(EVAS_CALLBACK_IMAGE_PRELOADED, func, *a, **k)

    def on_image_preloaded_del(self, func):
        """Same as event_callback_del(EVAS_CALLBACK_IMAGE_PRELOADED, ...)"""
        self.event_callback_del(EVAS_CALLBACK_IMAGE_PRELOADED, func)

    def on_image_unloaded_add(self, func, *a, **k):
        """Same as event_callback_add(EVAS_CALLBACK_IMAGE_UNLOADED, ...)"""
        self.event_callback_add(EVAS_CALLBACK_IMAGE_UNLOADED, func, *a, **k)

    def on_image_unloaded_del(self, func):
        """Same as event_callback_del(EVAS_CALLBACK_IMAGE_UNLOADED, ...)"""
        self.event_callback_del(EVAS_CALLBACK_IMAGE_UNLOADED, func)


_object_mapping_register("Evas_Image", Image)


cdef void _cb_on_filled_image_resize(void *data, Evas *e,
                                     Evas_Object *obj,
                                     void *event_info) with gil:
    cdef int w, h
    evas_object_geometry_get(obj, NULL, NULL, &w, &h)
    evas_object_image_fill_set(obj, 0, 0, w, h)


cdef class FilledImage(Image):

    """

    Image that automatically resize it's contents to fit object size.

    This :py:class:`Image` subclass already calls :py:attr:`Image.fill`
    on resize so it will match and so be scaled to fill the whole area.

    :param canvas: The evas canvas for this object
    :type canvas: :py:class:`~efl.evas.Canvas`
    :keyword size: Width and height
    :type size: tuple of ints
    :keyword pos: X and Y
    :type pos: tuple of ints
    :keyword geometry: X, Y, width, height
    :type geometry: tuple of ints
    :keyword color: R, G, B, A
    :type color: tuple of ints
    :keyword name: Object name
    :type name: string
    :keyword file: File name
    :type file: string

    """

    def __init__(self, Canvas canvas not None, **kargs):
        Image.__init__(self, canvas, **kargs)
        w, h = self.size_get()
        Image.fill_set(self, 0, 0, w, h)
        evas_object_event_callback_add(self.obj, EVAS_CALLBACK_RESIZE,
                                       _cb_on_filled_image_resize, NULL)

    def fill_set(self, int x, int y, int w, int h):
        """Not available for this class."""
        raise NotImplementedError("FilledImage doesn't support fill_set()")


#TODO: Check if this is right
_object_mapping_register("Evas_FilledImage", FilledImage)

def extension_can_load(filename):
    """extension_can_load(unicode filename) -> bool

    Check if a file extension is supported by :py:class:`Image`.

    :param filename: The file to check
    :type filename: unicode
    :return: ``True`` if we may be able to open it,``False`` if it's unlikely.
    :rtype: bool

    .. note:: This function is threadsafe.

    """
    if isinstance(filename, unicode): filename = PyUnicode_AsUTF8String(filename)
    return bool(evas_object_image_extension_can_load_get(
        <const_char *>filename))