advanced_topics.rst 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. ===============
  2. Advanced topics
  3. ===============
  4. .. _custom_image_model:
  5. Custom image model
  6. ==================
  7. The ``Image`` model can be customised, allowing additional fields to be added
  8. to images.
  9. To do this, you need to add two models to your project:
  10. - The image model itself that inherits from
  11. ``wagtail.wagtailimages.models.AbstractImage``. This is where you would add
  12. your additional fields
  13. - The renditions model that inherits from
  14. ``wagtail.wagtailimages.models.AbstractRendition``. This is used to store
  15. renditions for the new model.
  16. Here's an example:
  17. .. code-block:: python
  18. # models.py
  19. from django.db import models
  20. from django.db.models.signals import pre_delete
  21. from django.dispatch import receiver
  22. from wagtail.wagtailimages.models import Image, AbstractImage, AbstractRendition
  23. class CustomImage(AbstractImage):
  24. # Add any extra fields to image here
  25. # eg. To add a caption field:
  26. # caption = models.CharField(max_length=255)
  27. admin_form_fields = Image.admin_form_fields + (
  28. # Then add the field names here to make them appear in the form:
  29. # 'caption',
  30. )
  31. class CustomRendition(AbstractRendition):
  32. image = models.ForeignKey(CustomImage, related_name='renditions')
  33. class Meta:
  34. unique_together = (
  35. ('image', 'filter', 'focal_point_key'),
  36. )
  37. # Delete the source image file when an image is deleted
  38. @receiver(pre_delete, sender=CustomImage)
  39. def image_delete(sender, instance, **kwargs):
  40. instance.file.delete(False)
  41. # Delete the rendition image file when a rendition is deleted
  42. @receiver(pre_delete, sender=CustomRendition)
  43. def rendition_delete(sender, instance, **kwargs):
  44. instance.file.delete(False)
  45. .. note::
  46. If you are using image feature detection, follow these instructions to
  47. enable it on your custom image model: :ref:`feature_detection_custom_image_model`
  48. Then set the ``WAGTAILIMAGES_IMAGE_MODEL`` setting to point to it:
  49. .. code-block:: python
  50. WAGTAILIMAGES_IMAGE_MODEL = 'images.CustomImage'
  51. .. topic:: Migrating from the builtin image model
  52. When changing an existing site to use a custom image model. No images will
  53. be copied to the new model automatically. Copying old images to the new
  54. model would need to be done manually with a
  55. `data migration <https://docs.djangoproject.com/en/1.8/topics/migrations/#data-migrations>`_.
  56. Any templates that reference the builtin image model will still continue to
  57. work as before but would need to be updated in order to see any new images.
  58. Animated GIF support
  59. ====================
  60. Pillow (Wagtail's default image library) doesn't support resizing animated
  61. GIFs. If you need animated GIFs in your site, install
  62. `Wand <https://pypi.python.org/pypi/Wand>`_.
  63. When Wand is installed, Wagtail will automatically start using it for resizing
  64. GIF files, and will continue to resize other images with Pillow.
  65. .. _image_feature_detection:
  66. Feature Detection
  67. =================
  68. Wagtail has the ability to automatically detect faces and features inside your images and crop the images to those features.
  69. Feature detection uses OpenCV to detect faces/features in an image when the image is uploaded. The detected features stored internally as a focal point in the ``focal_point_{x, y, width, height}`` fields on the ``Image`` model. These fields are used by the ``fill`` image filter when an image is rendered in a template to crop the image.
  70. Setup
  71. -----
  72. Feature detection requires OpenCV which can be a bit tricky to install as it's not currently pip-installable.
  73. Installing OpenCV on Debian/Ubuntu
  74. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  75. Debian and ubuntu provide an apt-get package called ``python-opencv``:
  76. .. code-block:: sh
  77. sudo apt-get install python-opencv python-numpy
  78. This will install PyOpenCV into your site packages. If you are using a virtual environment, you need to make sure site packages are enabled or Wagtail will not be able to import PyOpenCV.
  79. Enabling site packages in the virtual environment
  80. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  81. If you are not using a virtual envionment, you can skip this step.
  82. Enabling site packages is different depending on whether you are using pyvenv (Python 3.3+ only) or virtualenv to manage your virtual environment.
  83. pyvenv
  84. ``````
  85. Go into your pyvenv directory and open the ``pyvenv.cfg`` file then set ``include-system-site-packages`` to ``true``.
  86. virtualenv
  87. ``````````
  88. Go into your virtualenv directory and delete a file called ``lib/python-x.x/no-global-site-packages.txt``.
  89. Testing the OpenCV installation
  90. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  91. You can test that OpenCV can be seen by Wagtail by opening up a python shell (with your virtual environment active) and typing:
  92. .. code-block:: python
  93. import cv
  94. If you don't see an ``ImportError``, it worked. (If you see the error ``libdc1394 error: Failed to initialize libdc1394``, this is harmless and can be ignored.)
  95. Switching on feature detection in Wagtail
  96. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  97. Once OpenCV is installed, you need to set the ``WAGTAILIMAGES_FEATURE_DETECTION_ENABLED`` setting to ``True``:
  98. .. code-block:: python
  99. # settings.py
  100. WAGTAILIMAGES_FEATURE_DETECTION_ENABLED = True
  101. Manually running feature detection
  102. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  103. Feature detection runs when new images are uploaded in to Wagtail. If you already have images in your Wagtail site and would like to run feature detection on them, you will have to run it manually.
  104. You can manually run feature detection on all images by running the following code in the python shell:
  105. .. code-block:: python
  106. from wagtail.wagtailimages.models import Image
  107. for image in Image.objects.all():
  108. if not image.has_focal_point():
  109. image.set_focal_point(image.get_suggested_focal_point())
  110. image.save()
  111. .. _feature_detection_custom_image_model:
  112. Feature detection and custom image models
  113. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  114. When using a :ref:`custom_image_model`, you need to add a signal handler to
  115. the model to trigger feature detection whenever a new image is uploaded:
  116. .. code-block:: python
  117. # Do feature detection when a user saves an image without a focal point
  118. @receiver(pre_save, sender=CustomImage)
  119. def image_feature_detection(sender, instance, **kwargs):
  120. # Make sure the image doesn't already have a focal point
  121. if not instance.has_focal_point():
  122. # Set the focal point
  123. instance.set_focal_point(instance.get_suggested_focal_point())
  124. .. note::
  125. This example will always run feature detection regardless of whether the
  126. ``WAGTAILIMAGES_FEATURE_DETECTION_ENABLED`` setting is set.
  127. Add a check for this setting if you still want it to have effect.