Blender V5.0
imbuf_py_api.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <Python.h>
12
13#include "BLI_string.h"
14#include "BLI_utildefines.h"
15
16#include "py_capi_utils.hh"
17
18#include "python_compat.hh" /* IWYU pragma: keep. */
19
20#include "imbuf_py_api.hh" /* own include */
21
24
25/* File IO */
26#include "BLI_fileops.h"
27#include <cerrno>
28#include <fcntl.h>
29
30static PyObject *BPyInit_imbuf_types();
31
32static PyObject *Py_ImBuf_CreatePyObject(ImBuf *ibuf);
33
34/* -------------------------------------------------------------------- */
37
38struct Py_ImBuf {
39 PyObject_VAR_HEAD
40 /* can be nullptr */
42};
43
45{
46 if (LIKELY(self->ibuf)) {
47 return 0;
48 }
49
50 PyErr_Format(
51 PyExc_ReferenceError, "ImBuf data of type %.200s has been freed", Py_TYPE(self)->tp_name);
52 return -1;
53}
54
55#define PY_IMBUF_CHECK_OBJ(obj) \
56 if (UNLIKELY(py_imbuf_valid_check(obj) == -1)) { \
57 return nullptr; \
58 } \
59 ((void)0)
60#define PY_IMBUF_CHECK_INT(obj) \
61 if (UNLIKELY(py_imbuf_valid_check(obj) == -1)) { \
62 return -1; \
63 } \
64 ((void)0)
65
67
68/* -------------------------------------------------------------------- */
71
73 /* Wrap. */
74 py_imbuf_resize_doc,
75 ".. method:: resize(size, *, method='FAST')\n"
76 "\n"
77 " Resize the image.\n"
78 "\n"
79 " :arg size: New size.\n"
80 " :type size: tuple[int, int]\n"
81 " :arg method: Method of resizing ('FAST', 'BILINEAR')\n"
82 " :type method: str\n");
83static PyObject *py_imbuf_resize(Py_ImBuf *self, PyObject *args, PyObject *kw)
84{
86
87 int size[2];
88
89 enum { FAST, BILINEAR };
90 const PyC_StringEnumItems method_items[] = {
91 {FAST, "FAST"},
92 {BILINEAR, "BILINEAR"},
93 {0, nullptr},
94 };
95 PyC_StringEnum method = {method_items, FAST};
96
97 static const char *_keywords[] = {"size", "method", nullptr};
98 static _PyArg_Parser _parser = {
100 "(ii)" /* `size` */
101 "|$" /* Optional keyword only arguments. */
102 "O&" /* `method` */
103 ":resize",
104 _keywords,
105 nullptr,
106 };
107 if (!_PyArg_ParseTupleAndKeywordsFast(
108 args, kw, &_parser, &size[0], &size[1], PyC_ParseStringEnum, &method))
109 {
110 return nullptr;
111 }
112 if (size[0] <= 0 || size[1] <= 0) {
113 PyErr_Format(PyExc_ValueError, "resize: Image size cannot be below 1 (%d, %d)", UNPACK2(size));
114 return nullptr;
115 }
116
117 if (method.value_found == FAST) {
119 }
120 else if (method.value_found == BILINEAR) {
122 }
123 else {
125 }
126 Py_RETURN_NONE;
127}
128
130 /* Wrap. */
131 py_imbuf_crop_doc,
132 ".. method:: crop(min, max)\n"
133 "\n"
134 " Crop the image.\n"
135 "\n"
136 " :arg min: X, Y minimum.\n"
137 " :type min: tuple[int, int]\n"
138 " :arg max: X, Y maximum.\n"
139 " :type max: tuple[int, int]\n");
140static PyObject *py_imbuf_crop(Py_ImBuf *self, PyObject *args, PyObject *kw)
141{
143
144 rcti crop;
145
146 static const char *_keywords[] = {"min", "max", nullptr};
147 static _PyArg_Parser _parser = {
149 "(II)" /* `min` */
150 "(II)" /* `max` */
151 ":crop",
152 _keywords,
153 nullptr,
154 };
155 if (!_PyArg_ParseTupleAndKeywordsFast(
156 args, kw, &_parser, &crop.xmin, &crop.ymin, &crop.xmax, &crop.ymax))
157 {
158 return nullptr;
159 }
160
161 if (/* X range. */
162 !(crop.xmin >= 0 && crop.xmax < self->ibuf->x) ||
163 /* Y range. */
164 !(crop.ymin >= 0 && crop.ymax < self->ibuf->y) ||
165 /* X order. */
166 !(crop.xmin <= crop.xmax) ||
167 /* Y order. */
168 !(crop.ymin <= crop.ymax))
169 {
170 PyErr_SetString(PyExc_ValueError, "ImBuf crop min/max not in range");
171 return nullptr;
172 }
173 IMB_rect_crop(self->ibuf, &crop);
174 Py_RETURN_NONE;
175}
176
178 /* Wrap. */
179 py_imbuf_copy_doc,
180 ".. method:: copy()\n"
181 "\n"
182 " :return: A copy of the image.\n"
183 " :rtype: :class:`ImBuf`\n");
184static PyObject *py_imbuf_copy(Py_ImBuf *self)
185{
187 ImBuf *ibuf_copy = IMB_dupImBuf(self->ibuf);
188
189 if (UNLIKELY(ibuf_copy == nullptr)) {
190 PyErr_SetString(PyExc_MemoryError,
191 "ImBuf.copy(): "
192 "failed to allocate memory");
193 return nullptr;
194 }
195 return Py_ImBuf_CreatePyObject(ibuf_copy);
196}
197
198static PyObject *py_imbuf_deepcopy(Py_ImBuf *self, PyObject *args)
199{
200 if (!PyC_CheckArgs_DeepCopy(args)) {
201 return nullptr;
202 }
203 return py_imbuf_copy(self);
204}
205
207 /* Wrap. */
208 py_imbuf_free_doc,
209 ".. method:: free()\n"
210 "\n"
211 " Clear image data immediately (causing an error on re-use).\n");
212static PyObject *py_imbuf_free(Py_ImBuf *self)
213{
214 if (self->ibuf) {
215 IMB_freeImBuf(self->ibuf);
216 self->ibuf = nullptr;
217 }
218 Py_RETURN_NONE;
219}
220
221#ifdef __GNUC__
222# ifdef __clang__
223# pragma clang diagnostic push
224# pragma clang diagnostic ignored "-Wcast-function-type"
225# else
226# pragma GCC diagnostic push
227# pragma GCC diagnostic ignored "-Wcast-function-type"
228# endif
229#endif
230
231static PyMethodDef Py_ImBuf_methods[] = {
232 {"resize", (PyCFunction)py_imbuf_resize, METH_VARARGS | METH_KEYWORDS, py_imbuf_resize_doc},
233 {"crop", (PyCFunction)py_imbuf_crop, METH_VARARGS | METH_KEYWORDS, (char *)py_imbuf_crop_doc},
234 {"free", (PyCFunction)py_imbuf_free, METH_NOARGS, py_imbuf_free_doc},
235 {"copy", (PyCFunction)py_imbuf_copy, METH_NOARGS, py_imbuf_copy_doc},
236 {"__copy__", (PyCFunction)py_imbuf_copy, METH_NOARGS, py_imbuf_copy_doc},
237 {"__deepcopy__", (PyCFunction)py_imbuf_deepcopy, METH_VARARGS, py_imbuf_copy_doc},
238 {nullptr, nullptr, 0, nullptr},
239};
240
241#ifdef __GNUC__
242# ifdef __clang__
243# pragma clang diagnostic pop
244# else
245# pragma GCC diagnostic pop
246# endif
247#endif
248
250
251/* -------------------------------------------------------------------- */
254
256 /* Wrap. */
257 py_imbuf_size_doc,
258 "size of the image in pixels.\n"
259 "\n"
260 ":type: tuple[int, int]\n");
261static PyObject *py_imbuf_size_get(Py_ImBuf *self, void * /*closure*/)
262{
264 ImBuf *ibuf = self->ibuf;
265 return PyC_Tuple_Pack_I32({ibuf->x, ibuf->y});
266}
267
269 /* Wrap. */
270 py_imbuf_ppm_doc,
271 "pixels per meter.\n"
272 "\n"
273 ":type: tuple[float, float]\n");
274static PyObject *py_imbuf_ppm_get(Py_ImBuf *self, void * /*closure*/)
275{
277 ImBuf *ibuf = self->ibuf;
278 return PyC_Tuple_Pack_F64({ibuf->ppm[0], ibuf->ppm[1]});
279}
280
281static int py_imbuf_ppm_set(Py_ImBuf *self, PyObject *value, void * /*closure*/)
282{
284 double ppm[2];
285
286 if (PyC_AsArray(ppm, sizeof(*ppm), value, 2, &PyFloat_Type, "ppm") == -1) {
287 return -1;
288 }
289
290 if (ppm[0] <= 0.0 || ppm[1] <= 0.0) {
291 PyErr_SetString(PyExc_ValueError, "invalid ppm value");
292 return -1;
293 }
294
295 ImBuf *ibuf = self->ibuf;
296 ibuf->ppm[0] = ppm[0];
297 ibuf->ppm[1] = ppm[1];
298 return 0;
299}
300
302 /* Wrap. */
303 py_imbuf_filepath_doc,
304 "filepath associated with this image.\n"
305 "\n"
306 ":type: str\n");
307static PyObject *py_imbuf_filepath_get(Py_ImBuf *self, void * /*closure*/)
308{
310 ImBuf *ibuf = self->ibuf;
311 return PyC_UnicodeFromBytes(ibuf->filepath);
312}
313
314static int py_imbuf_filepath_set(Py_ImBuf *self, PyObject *value, void * /*closure*/)
315{
317
318 if (!PyUnicode_Check(value)) {
319 PyErr_SetString(PyExc_TypeError, "expected a string!");
320 return -1;
321 }
322
323 ImBuf *ibuf = self->ibuf;
324 const Py_ssize_t value_str_len_max = sizeof(ibuf->filepath);
325 PyObject *value_coerce = nullptr;
326 Py_ssize_t value_str_len;
327 const char *value_str = PyC_UnicodeAsBytesAndSize(value, &value_str_len, &value_coerce);
328 if (value_str_len >= value_str_len_max) {
329 PyErr_Format(PyExc_TypeError, "filepath length over %zd", value_str_len_max - 1);
330 Py_XDECREF(value_coerce);
331 return -1;
332 }
333 memcpy(ibuf->filepath, value_str, value_str_len + 1);
334 Py_XDECREF(value_coerce);
335 return 0;
336}
337
339 /* Wrap. */
340 py_imbuf_planes_doc,
341 "Number of bits associated with this image.\n"
342 "\n"
343 ":type: int\n");
344static PyObject *py_imbuf_planes_get(Py_ImBuf *self, void * /*closure*/)
345{
347 ImBuf *imbuf = self->ibuf;
348 return PyLong_FromLong(imbuf->planes);
349}
350
352 /* Wrap. */
353 py_imbuf_channels_doc,
354 "Number of bit-planes.\n"
355 "\n"
356 ":type: int\n");
357static PyObject *py_imbuf_channels_get(Py_ImBuf *self, void * /*closure*/)
358{
360 ImBuf *imbuf = self->ibuf;
361 return PyLong_FromLong(imbuf->channels);
362}
363
364static PyGetSetDef Py_ImBuf_getseters[] = {
365 {"size", (getter)py_imbuf_size_get, (setter) nullptr, py_imbuf_size_doc, nullptr},
366 {"ppm", (getter)py_imbuf_ppm_get, (setter)py_imbuf_ppm_set, py_imbuf_ppm_doc, nullptr},
367 {"filepath",
368 (getter)py_imbuf_filepath_get,
369 (setter)py_imbuf_filepath_set,
370 py_imbuf_filepath_doc,
371 nullptr},
372 {"planes", (getter)py_imbuf_planes_get, nullptr, py_imbuf_planes_doc, nullptr},
373 {"channels", (getter)py_imbuf_channels_get, nullptr, py_imbuf_channels_doc, nullptr},
374 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
375};
376
378
379/* -------------------------------------------------------------------- */
382
384{
385 ImBuf *ibuf = self->ibuf;
386 if (ibuf != nullptr) {
387 IMB_freeImBuf(self->ibuf);
388 self->ibuf = nullptr;
389 }
390 PyObject_DEL(self);
391}
392
393static PyObject *py_imbuf_repr(Py_ImBuf *self)
394{
395 const ImBuf *ibuf = self->ibuf;
396 if (ibuf != nullptr) {
397 return PyUnicode_FromFormat("<imbuf: address=%p, filepath='%s', size=(%d, %d)>",
398 ibuf,
399 ibuf->filepath,
400 ibuf->x,
401 ibuf->y);
402 }
403
404 return PyUnicode_FromString("<imbuf: address=0x0>");
405}
406
407static Py_hash_t py_imbuf_hash(Py_ImBuf *self)
408{
409 return Py_HashPointer(self->ibuf);
410}
411
412PyTypeObject Py_ImBuf_Type = {
413 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
414 /*tp_name*/ "ImBuf",
415 /*tp_basicsize*/ sizeof(Py_ImBuf),
416 /*tp_itemsize*/ 0,
417 /*tp_dealloc*/ (destructor)py_imbuf_dealloc,
418 /*tp_vectorcall_offset*/ 0,
419 /*tp_getattr*/ nullptr,
420 /*tp_setattr*/ nullptr,
421 /*tp_as_async*/ nullptr,
422 /*tp_repr*/ (reprfunc)py_imbuf_repr,
423 /*tp_as_number*/ nullptr,
424 /*tp_as_sequence*/ nullptr,
425 /*tp_as_mapping*/ nullptr,
426 /*tp_hash*/ (hashfunc)py_imbuf_hash,
427 /*tp_call*/ nullptr,
428 /*tp_str*/ nullptr,
429 /*tp_getattro*/ nullptr,
430 /*tp_setattro*/ nullptr,
431 /*tp_as_buffer*/ nullptr,
432 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
433 /*tp_doc*/ nullptr,
434 /*tp_traverse*/ nullptr,
435 /*tp_clear*/ nullptr,
436 /*tp_richcompare*/ nullptr,
437 /*tp_weaklistoffset*/ 0,
438 /*tp_iter*/ nullptr,
439 /*tp_iternext*/ nullptr,
440 /*tp_methods*/ Py_ImBuf_methods,
441 /*tp_members*/ nullptr,
442 /*tp_getset*/ Py_ImBuf_getseters,
443 /*tp_base*/ nullptr,
444 /*tp_dict*/ nullptr,
445 /*tp_descr_get*/ nullptr,
446 /*tp_descr_set*/ nullptr,
447 /*tp_dictoffset*/ 0,
448 /*tp_init*/ nullptr,
449 /*tp_alloc*/ nullptr,
450 /*tp_new*/ nullptr,
451 /*tp_free*/ nullptr,
452 /*tp_is_gc*/ nullptr,
453 /*tp_bases*/ nullptr,
454 /*tp_mro*/ nullptr,
455 /*tp_cache*/ nullptr,
456 /*tp_subclasses*/ nullptr,
457 /*tp_weaklist*/ nullptr,
458 /*tp_del*/ nullptr,
459 /*tp_version_tag*/ 0,
460 /*tp_finalize*/ nullptr,
461 /*tp_vectorcall*/ nullptr,
462};
463
464static PyObject *Py_ImBuf_CreatePyObject(ImBuf *ibuf)
465{
466 Py_ImBuf *self = PyObject_New(Py_ImBuf, &Py_ImBuf_Type);
467 self->ibuf = ibuf;
468 return (PyObject *)self;
469}
470
472
473/* -------------------------------------------------------------------- */
476
478 /* Wrap. */
479 M_imbuf_new_doc,
480 ".. function:: new(size)\n"
481 "\n"
482 " Load a new image.\n"
483 "\n"
484 " :arg size: The size of the image in pixels.\n"
485 " :type size: tuple[int, int]\n"
486 " :return: the newly loaded image.\n"
487 " :rtype: :class:`ImBuf`\n");
488static PyObject *M_imbuf_new(PyObject * /*self*/, PyObject *args, PyObject *kw)
489{
490 int size[2];
491 static const char *_keywords[] = {"size", nullptr};
492 static _PyArg_Parser _parser = {
494 "(ii)" /* `size` */
495 ":new",
496 _keywords,
497 nullptr,
498 };
499 if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &size[0], &size[1])) {
500 return nullptr;
501 }
502 if (size[0] <= 0 || size[1] <= 0) {
503 PyErr_Format(PyExc_ValueError, "new: Image size cannot be below 1 (%d, %d)", UNPACK2(size));
504 return nullptr;
505 }
506
507 /* TODO: make options. */
508 const uchar planes = 32;
509 const uint flags = IB_byte_data;
510
511 ImBuf *ibuf = IMB_allocImBuf(UNPACK2(size), planes, flags);
512 if (ibuf == nullptr) {
513 PyErr_Format(PyExc_ValueError, "new: Unable to create image (%d, %d)", UNPACK2(size));
514 return nullptr;
515 }
516 return Py_ImBuf_CreatePyObject(ibuf);
517}
518
519static PyObject *imbuf_load_impl(const char *filepath)
520{
521 const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
522 if (file == -1) {
523 PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno), filepath);
524 return nullptr;
525 }
526
528
529 close(file);
530
531 if (ibuf == nullptr) {
532 PyErr_Format(
533 PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filepath);
534 return nullptr;
535 }
536
537 STRNCPY(ibuf->filepath, filepath);
538
539 return Py_ImBuf_CreatePyObject(ibuf);
540}
541
543 /* Wrap. */
544 M_imbuf_load_doc,
545 ".. function:: load(filepath)\n"
546 "\n"
547 " Load an image from a file.\n"
548 "\n"
549 " :arg filepath: the filepath of the image.\n"
550 " :type filepath: str | bytes\n"
551 " :return: the newly loaded image.\n"
552 " :rtype: :class:`ImBuf`\n");
553static PyObject *M_imbuf_load(PyObject * /*self*/, PyObject *args, PyObject *kw)
554{
555 PyC_UnicodeAsBytesAndSize_Data filepath_data = {nullptr};
556
557 static const char *_keywords[] = {"filepath", nullptr};
558 static _PyArg_Parser _parser = {
560 "O&" /* `filepath` */
561 ":load",
562 _keywords,
563 nullptr,
564 };
565 if (!_PyArg_ParseTupleAndKeywordsFast(
566 args, kw, &_parser, PyC_ParseUnicodeAsBytesAndSize, &filepath_data))
567 {
568 return nullptr;
569 }
570
571 PyObject *result = imbuf_load_impl(filepath_data.value);
572 Py_XDECREF(filepath_data.value_coerce);
573 return result;
574}
575
576static PyObject *imbuf_load_from_memory_impl(const char *buffer,
577 const size_t buffer_size,
578 int flags)
579{
581 reinterpret_cast<const uchar *>(buffer), buffer_size, flags, "<imbuf.load_from_buffer>");
582
583 if (ibuf == nullptr) {
584 PyErr_SetString(PyExc_ValueError, "load_from_buffer: Unable to load image from memory");
585 return nullptr;
586 }
587
588 return Py_ImBuf_CreatePyObject(ibuf);
589}
590
592 /* Wrap. */
593 M_imbuf_load_from_buffer_doc,
594 ".. function:: load_from_buffer(buffer)\n"
595 "\n"
596 " Load an image from a buffer.\n"
597 "\n"
598 " :arg buffer: A buffer containing the image data.\n"
599 " :type buffer: collections.abc.Buffer\n"
600 " :return: the newly loaded image.\n"
601 " :rtype: :class:`ImBuf`\n");
602static PyObject *M_imbuf_load_from_buffer(PyObject * /*self*/, PyObject *args, PyObject *kw)
603{
604 PyObject *buffer_py_ob;
605
606 static const char *_keywords[] = {"buffer", nullptr};
607 static _PyArg_Parser _parser = {
609 "O" /* `buffer` */
610 ":load_from_buffer",
611 _keywords,
612 nullptr,
613 };
614 if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &buffer_py_ob)) {
615 return nullptr;
616 }
617
618 PyObject *result = nullptr;
619 /* TODO: should be arguments. */
620 int flags = IB_byte_data;
621
622 /* This supports `PyBytes`, no need for a separate check. */
623 if (PyObject_CheckBuffer(buffer_py_ob)) {
624 Py_buffer pybuffer;
625 if (PyObject_GetBuffer(buffer_py_ob, &pybuffer, PyBUF_SIMPLE) == -1) {
626 return nullptr;
627 }
629 reinterpret_cast<const char *>(pybuffer.buf), pybuffer.len, flags);
630
631 PyBuffer_Release(&pybuffer);
632 }
633 else {
634 PyErr_Format(PyExc_TypeError,
635 "load_from_buffer: expected a buffer, unsupported type %.200s",
636 Py_TYPE(buffer_py_ob)->tp_name);
637 return nullptr;
638 }
639 return result;
640}
641
642static PyObject *imbuf_write_impl(ImBuf *ibuf, const char *filepath)
643{
644 const bool ok = IMB_save_image(ibuf, filepath, IB_byte_data);
645 if (ok == false) {
646 PyErr_Format(
647 PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filepath);
648 return nullptr;
649 }
650 Py_RETURN_NONE;
651}
652
654 /* Wrap. */
655 M_imbuf_write_doc,
656 ".. function:: write(image, *, filepath=image.filepath)\n"
657 "\n"
658 " Write an image.\n"
659 "\n"
660 " :arg image: the image to write.\n"
661 " :type image: :class:`ImBuf`\n"
662 " :arg filepath: Optional filepath of the image (fallback to the images file path).\n"
663 " :type filepath: str | bytes | None\n");
664static PyObject *M_imbuf_write(PyObject * /*self*/, PyObject *args, PyObject *kw)
665{
666 Py_ImBuf *py_imb;
667 PyC_UnicodeAsBytesAndSize_Data filepath_data = {nullptr};
668
669 static const char *_keywords[] = {"image", "filepath", nullptr};
670 static _PyArg_Parser _parser = {
672 "O!" /* `image` */
673 "|$" /* Optional keyword only arguments. */
674 "O&" /* `filepath` */
675 ":write",
676 _keywords,
677 nullptr,
678 };
679 if (!_PyArg_ParseTupleAndKeywordsFast(args,
680 kw,
681 &_parser,
683 &py_imb,
685 &filepath_data))
686 {
687 return nullptr;
688 }
689
690 const char *filepath = filepath_data.value;
691 if (filepath == nullptr) {
692 /* Argument omitted, use images path. */
693 filepath = py_imb->ibuf->filepath;
694 }
695 PyObject *result = imbuf_write_impl(py_imb->ibuf, filepath);
696 Py_XDECREF(filepath_data.value_coerce);
697 return result;
698}
699
701
702/* -------------------------------------------------------------------- */
705
706#ifdef __GNUC__
707# ifdef __clang__
708# pragma clang diagnostic push
709# pragma clang diagnostic ignored "-Wcast-function-type"
710# else
711# pragma GCC diagnostic push
712# pragma GCC diagnostic ignored "-Wcast-function-type"
713# endif
714#endif
715
716static PyMethodDef IMB_methods[] = {
717 {"new", (PyCFunction)M_imbuf_new, METH_VARARGS | METH_KEYWORDS, M_imbuf_new_doc},
718 {"load", (PyCFunction)M_imbuf_load, METH_VARARGS | METH_KEYWORDS, M_imbuf_load_doc},
719 {"load_from_buffer",
720 (PyCFunction)M_imbuf_load_from_buffer,
721 METH_VARARGS | METH_KEYWORDS,
722 M_imbuf_load_from_buffer_doc},
723 {"write", (PyCFunction)M_imbuf_write, METH_VARARGS | METH_KEYWORDS, M_imbuf_write_doc},
724 {nullptr, nullptr, 0, nullptr},
725};
726
727#ifdef __GNUC__
728# ifdef __clang__
729# pragma clang diagnostic pop
730# else
731# pragma GCC diagnostic pop
732# endif
733#endif
734
736 /* Wrap. */
737 IMB_doc,
738 "This module provides access to Blender's image manipulation API.\n"
739 "\n"
740 "It provides access to image buffers outside of Blender's\n"
741 ":class:`bpy.types.Image` data-block context.\n");
742static PyModuleDef IMB_module_def = {
743 /*m_base*/ PyModuleDef_HEAD_INIT,
744 /*m_name*/ "imbuf",
745 /*m_doc*/ IMB_doc,
746 /*m_size*/ 0,
747 /*m_methods*/ IMB_methods,
748 /*m_slots*/ nullptr,
749 /*m_traverse*/ nullptr,
750 /*m_clear*/ nullptr,
751 /*m_free*/ nullptr,
752};
753
754PyObject *BPyInit_imbuf()
755{
756 PyObject *mod;
757 PyObject *submodule;
758 PyObject *sys_modules = PyImport_GetModuleDict();
759
760 mod = PyModule_Create(&IMB_module_def);
761
762 /* `imbuf.types` */
763 PyModule_AddObject(mod, "types", (submodule = BPyInit_imbuf_types()));
764 PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
765
766 return mod;
767}
768
770
771/* -------------------------------------------------------------------- */
777
779 /* Wrap. */
780 IMB_types_doc,
781 "This module provides access to image buffer types.\n"
782 "\n"
783 ".. note::\n"
784 "\n"
785 " Image buffer is also the structure used by :class:`bpy.types.Image`\n"
786 " ID type to store and manipulate image data at runtime.\n");
787static PyModuleDef IMB_types_module_def = {
788 /*m_base*/ PyModuleDef_HEAD_INIT,
789 /*m_name*/ "imbuf.types",
790 /*m_doc*/ IMB_types_doc,
791 /*m_size*/ 0,
792 /*m_methods*/ nullptr,
793 /*m_slots*/ nullptr,
794 /*m_traverse*/ nullptr,
795 /*m_clear*/ nullptr,
796 /*m_free*/ nullptr,
797};
798
800{
801 PyObject *submodule = PyModule_Create(&IMB_types_module_def);
802
803 if (PyType_Ready(&Py_ImBuf_Type) < 0) {
804 return nullptr;
805 }
806
807 PyModule_AddType(submodule, &Py_ImBuf_Type);
808
809 return submodule;
810}
811
813
814/* -------------------------------------------------------------------- */
817
818ImBuf *BPy_ImBuf_FromPyObject(PyObject *py_imbuf)
819{
820 /* The caller must ensure this. */
821 BLI_assert(Py_TYPE(py_imbuf) == &Py_ImBuf_Type);
822
823 if (py_imbuf_valid_check((Py_ImBuf *)py_imbuf) == -1) {
824 return nullptr;
825 }
826
827 return ((Py_ImBuf *)py_imbuf)->ibuf;
828}
829
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
File and directory operations.
#define O_BINARY
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
unsigned char uchar
unsigned int uint
#define UNPACK2(a)
#define UNLIKELY(x)
#define LIKELY(x)
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
ImBuf * IMB_load_image_from_memory(const unsigned char *mem, const size_t size, const int flags, const char *descr, const char *filepath=nullptr, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:121
void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
Definition rectop.cc:241
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
ImBuf * IMB_load_image_from_file_descriptor(const int file, const int flags, const char *filepath=nullptr, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:155
bool IMB_save_image(ImBuf *ibuf, const char *filepath, const int flags)
Definition writeimage.cc:23
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:465
@ IB_byte_data
PyObject * self
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
static PyObject * Py_ImBuf_CreatePyObject(ImBuf *ibuf)
static PyObject * py_imbuf_filepath_get(Py_ImBuf *self, void *)
static PyObject * M_imbuf_load(PyObject *, PyObject *args, PyObject *kw)
static PyObject * py_imbuf_planes_get(Py_ImBuf *self, void *)
static PyObject * py_imbuf_channels_get(Py_ImBuf *self, void *)
static int py_imbuf_filepath_set(Py_ImBuf *self, PyObject *value, void *)
static PyObject * M_imbuf_write(PyObject *, PyObject *args, PyObject *kw)
static PyObject * py_imbuf_size_get(Py_ImBuf *self, void *)
static PyObject * imbuf_load_impl(const char *filepath)
static PyObject * BPyInit_imbuf_types()
static PyObject * py_imbuf_copy(Py_ImBuf *self)
static PyObject * py_imbuf_resize(Py_ImBuf *self, PyObject *args, PyObject *kw)
static Py_hash_t py_imbuf_hash(Py_ImBuf *self)
#define PY_IMBUF_CHECK_OBJ(obj)
static PyMethodDef IMB_methods[]
static PyObject * M_imbuf_new(PyObject *, PyObject *args, PyObject *kw)
#define PY_IMBUF_CHECK_INT(obj)
static PyObject * py_imbuf_ppm_get(Py_ImBuf *self, void *)
static PyModuleDef IMB_module_def
static PyObject * py_imbuf_crop(Py_ImBuf *self, PyObject *args, PyObject *kw)
static int py_imbuf_ppm_set(Py_ImBuf *self, PyObject *value, void *)
static PyObject * py_imbuf_repr(Py_ImBuf *self)
PyDoc_STRVAR(py_imbuf_resize_doc, ".. method:: resize(size, *, method='FAST')\n" "\n" " Resize the image.\n" "\n" " :arg size: New size.\n" " :type size: tuple[int, int]\n" " :arg method: Method of resizing ('FAST', 'BILINEAR')\n" " :type method: str\n")
static PyObject * imbuf_write_impl(ImBuf *ibuf, const char *filepath)
PyObject * BPyInit_imbuf()
static PyObject * py_imbuf_free(Py_ImBuf *self)
static PyGetSetDef Py_ImBuf_getseters[]
PyTypeObject Py_ImBuf_Type
static PyMethodDef Py_ImBuf_methods[]
ImBuf * BPy_ImBuf_FromPyObject(PyObject *py_imbuf)
static int py_imbuf_valid_check(Py_ImBuf *self)
static PyModuleDef IMB_types_module_def
static void py_imbuf_dealloc(Py_ImBuf *self)
static PyObject * py_imbuf_deepcopy(Py_ImBuf *self, PyObject *args)
static PyObject * M_imbuf_load_from_buffer(PyObject *, PyObject *args, PyObject *kw)
static PyObject * imbuf_load_from_memory_impl(const char *buffer, const size_t buffer_size, int flags)
const char * PyC_UnicodeAsBytesAndSize(PyObject *py_str, Py_ssize_t *r_size, PyObject **r_coerce)
int PyC_CheckArgs_DeepCopy(PyObject *args)
int PyC_ParseUnicodeAsBytesAndSize(PyObject *o, void *p)
int PyC_ParseStringEnum(PyObject *o, void *p)
PyObject * PyC_UnicodeFromBytes(const char *str)
int PyC_AsArray(void *array, const size_t array_item_size, PyObject *value, const Py_ssize_t length, const PyTypeObject *type, const char *error_prefix)
int PyC_ParseUnicodeAsBytesAndSize_OrNone(PyObject *o, void *p)
PyObject * PyC_Tuple_Pack_I32(const blender::Span< int > values)
PyObject * PyC_Tuple_Pack_F64(const blender::Span< double > values)
header-only compatibility defines.
#define Py_HashPointer
#define PY_ARG_PARSER_HEAD_COMPAT()
char filepath[IMB_FILEPATH_SIZE]
unsigned char planes
double ppm[2]
PyObject_VAR_HEAD ImBuf * ibuf
int ymin
int ymax
int xmin
int xmax