Repository: scikit-image/scikit-image

Issue:
Optimize gallery images with optipng
## Purpose

This issue follows the PR #4613, the[ issue reported to sphinx-gallery](https://github.com/sphinx-gallery/sphinx-gallery/issues/655) and the addition of optipng proposed by @larsoner in [this PR](https://github.com/sphinx-gallery/sphinx-gallery/pull/656).

I would like to keep track of trials in our issue tracker, that's why I open this ticket.


## Test 

I build sphinx-gallery with the patch proposed in the PR, cleaned our doc and re-built it.

This result has to be compared with the "compressed" data in #4613 since the PR was merged before this test.

with optipng -o7
```
 29K 28 avril 11:38 sphx_glr_plot_active_contours_thumb.png
 35K 28 avril 11:34 sphx_glr_plot_adapt_rgb_thumb.png
 14K 28 avril 11:49 sphx_glr_plot_attribute_operators_thumb.png
 43K 28 avril 11:51 sphx_glr_plot_blob_thumb.png
 73K 28 avril 11:58 sphx_glr_plot_boundary_merge_thumb.png
 35K 28 avril 11:51 sphx_glr_plot_brief_thumb.png
 11K 28 avril 11:31 sphx_glr_plot_camera_numpy_thumb.png
8,5K 28 avril 11:36 sphx_glr_plot_canny_thumb.png
 37K 28 avril 11:50 sphx_glr_plot_censure_thumb.png
 24K 28 avril 11:54 sphx_glr_plot_chan_vese_thumb.png
 22K 28 avril 11:39 sphx_glr_plot_circular_elliptical_hough_transform_thumb.png
 16K 28 avril 12:05 sphx_glr_plot_coins_segmentation_thumb.png
 36K 28 avril 11:53 sphx_glr_plot_compact_watershed_thumb.png
 21K 28 avril 11:36 sphx_glr_plot_contours_thumb.png
3,7K 28 avril 11:36 sphx_glr_plot_convex_hull_thumb.png
9,8K 28 avril 11:50 sphx_glr_plot_corner_thumb.png
 31K 28 avril 11:48 sphx_glr_plot_cycle_spinning_thumb.png
 49K 28 avril 11:49 sphx_glr_plot_daisy_thumb.png
 20K 28 avril 11:47 sphx_glr_plot_deconvolution_thumb.png
 41K 28 avril 11:48 sphx_glr_plot_denoise_thumb.png
3,6K 28 avril 11:49 sphx_glr_plot_denoise_wavelet_thumb.png
 37K 28 avril 11:48 sphx_glr_plot_dog_thumb.png
 19K 28 avril 11:40 sphx_glr_plot_edge_filter_thumb.png
9,2K 28 avril 11:40 sphx_glr_plot_edge_modes_thumb.png
 27K 28 avril 11:47 sphx_glr_plot_entropy_thumb.png
 26K 28 avril 11:35 sphx_glr_plot_equalize_thumb.png
 21K 28 avril 11:58 sphx_glr_plot_extrema_thumb.png
 45K 28 avril 12:03 sphx_glr_plot_face_detection_thumb.png
2,7K 28 avril 12:02 sphx_glr_plot_floodfill_thumb.png
 27K 28 avril 11:42 sphx_glr_plot_fundamental_matrix_thumb.png
 19K 28 avril 11:51 sphx_glr_plot_gabors_from_astronaut_thumb.png
 13K 28 avril 11:52 sphx_glr_plot_gabor_thumb.png
 48K 28 avril 11:31 sphx_glr_plot_general_thumb.png
 14K 28 avril 11:41 sphx_glr_plot_geometric_thumb.png
 19K 28 avril 11:51 sphx_glr_plot_glcm_thumb.png
 18K 28 avril 12:08 sphx_glr_plot_haar_extraction_selection_classification_thumb.png
2,0K 28 avril 11:50 sphx_glr_plot_haar_thumb.png
 35K 28 avril 11:33 sphx_glr_plot_histogram_matching_thumb.png
 38K 28 avril 11:49 sphx_glr_plot_hog_thumb.png
 12K 28 avril 11:50 sphx_glr_plot_holes_and_peaks_thumb.png
 53K 28 avril 11:45 sphx_glr_plot_hysteresis_thumb.png
 58K 28 avril 11:33 sphx_glr_plot_ihc_color_separation_thumb.png
 20K 28 avril 12:04 sphx_glr_plot_image_comparison_thumb.png
 37K 28 avril 11:47 sphx_glr_plot_inpaint_thumb.png
 39K 28 avril 11:57 sphx_glr_plot_join_segmentations_thumb.png
 42K 28 avril 11:55 sphx_glr_plot_label_thumb.png
6,1K 28 avril 11:38 sphx_glr_plot_line_hough_transform_thumb.png
3,1K 28 avril 11:53 sphx_glr_plot_local_binary_pattern_thumb.png
 29K 28 avril 11:35 sphx_glr_plot_local_equalize_thumb.png
 21K 28 avril 11:35 sphx_glr_plot_log_gamma_thumb.png
 31K 28 avril 11:37 sphx_glr_plot_marching_cubes_thumb.png
 41K 28 avril 11:56 sphx_glr_plot_marked_watershed_thumb.png
 11K 28 avril 11:42 sphx_glr_plot_masked_register_translation_thumb.png
 32K 28 avril 11:43 sphx_glr_plot_matching_thumb.png
 11K 28 avril 12:15 sphx_glr_plot_max_tree_thumb.png
 46K 28 avril 12:03 sphx_glr_plot_metrics_thumb.png
4,9K 28 avril 12:04 sphx_glr_plot_morphology_thumb.png
 44K 28 avril 12:02 sphx_glr_plot_morphsnakes_thumb.png
 35K 28 avril 11:50 sphx_glr_plot_multiblock_local_binary_pattern_thumb.png
 16K 28 avril 11:55 sphx_glr_plot_multiotsu_thumb.png
 26K 28 avril 11:53 sphx_glr_plot_ncut_thumb.png
8,8K 28 avril 11:54 sphx_glr_plot_niblack_sauvola_thumb.png
 56K 28 avril 11:49 sphx_glr_plot_nonlocal_means_thumb.png
 31K 28 avril 11:43 sphx_glr_plot_opticalflow_thumb.png
 42K 28 avril 11:51 sphx_glr_plot_orb_thumb.png
 24K 28 avril 11:54 sphx_glr_plot_peak_local_max_thumb.png
 15K 28 avril 11:48 sphx_glr_plot_phase_unwrap_thumb.png
 49K 28 avril 11:40 sphx_glr_plot_piecewise_affine_thumb.png
 12K 28 avril 11:39 sphx_glr_plot_polygon_thumb.png
 52K 28 avril 11:40 sphx_glr_plot_pyramid_thumb.png
 13K 28 avril 11:42 sphx_glr_plot_radon_transform_thumb.png
 58K 28 avril 11:53 sphx_glr_plot_rag_boundary_thumb.png
 54K 28 avril 11:54 sphx_glr_plot_rag_draw_thumb.png
 27K 28 avril 11:53 sphx_glr_plot_rag_mean_color_thumb.png
 33K 28 avril 11:57 sphx_glr_plot_rag_merge_thumb.png
9,9K 28 avril 11:57 sphx_glr_plot_rag_thumb.png
9,5K 28 avril 11:38 sphx_glr_plot_random_shapes_thumb.png
 40K 28 avril 11:55 sphx_glr_plot_random_walker_segmentation_thumb.png
 21K 28 avril 12:14 sphx_glr_plot_rank_filters_thumb.png
 18K 28 avril 11:46 sphx_glr_plot_rank_mean_thumb.png
 12K 28 avril 11:42 sphx_glr_plot_ransac_thumb.png
 12K 28 avril 11:34 sphx_glr_plot_regional_maxima_thumb.png
 11K 28 avril 11:58 sphx_glr_plot_regionprops_table_thumb.png
6,2K 28 avril 11:57 sphx_glr_plot_regionprops_thumb.png
 29K 28 avril 11:45 sphx_glr_plot_register_rotation_thumb.png
 17K 28 avril 11:43 sphx_glr_plot_register_translation_thumb.png
 21K 28 avril 11:40 sphx_glr_plot_rescale_thumb.png
 24K 28 avril 11:45 sphx_glr_plot_restoration_thumb.png
 49K 28 avril 11:32 sphx_glr_plot_rgb_to_gray_thumb.png
 30K 28 avril 11:32 sphx_glr_plot_rgb_to_hsv_thumb.png
 28K 28 avril 11:36 sphx_glr_plot_ridge_filter_thumb.png
 51K 28 avril 11:29 sphx_glr_plot_scientific_thumb.png
 80K 28 avril 11:57 sphx_glr_plot_segmentations_thumb.png
 33K 28 avril 11:52 sphx_glr_plot_shape_index_thumb.png
6,7K 28 avril 11:38 sphx_glr_plot_shapes_thumb.png
4,2K 28 avril 11:39 sphx_glr_plot_skeleton_thumb.png
 39K 28 avril 11:28 sphx_glr_plot_specific_thumb.png
 17K 28 avril 11:41 sphx_glr_plot_ssim_thumb.png
 42K 28 avril 11:31 sphx_glr_plot_structuring_elements_thumb.png
4,7K 28 avril 11:40 sphx_glr_plot_swirl_thumb.png
 18K 28 avril 11:50 sphx_glr_plot_template_thumb.png
 13K 28 avril 12:05 sphx_glr_plot_thresholding_thumb1.png
 13K 28 avril 11:54 sphx_glr_plot_thresholding_thumb.png
 15K 28 avril 12:14 sphx_glr_plot_threshold_li_thumb.png
 23K 28 avril 11:36 sphx_glr_plot_tinting_grayscale_images_thumb.png
8,5K 28 avril 11:45 sphx_glr_plot_tophat_thumb.png
 19K 28 avril 11:41 sphx_glr_plot_transform_types_thumb.png
 18K 28 avril 11:47 sphx_glr_plot_unsharp_mask_thumb.png
 22K 28 avril 11:32 sphx_glr_plot_view_as_blocks_thumb.png
2,6K 28 avril 11:55 sphx_glr_plot_watershed_thumb.png
 38K 28 avril 11:52 sphx_glr_plot_windowed_histogram_thumb.png
 31K 28 avril 11:46 sphx_glr_plot_window_thumb.png
```

patch modified, to use pngquant

```
 36K sphx_glr_plot_active_contours_thumb.png
 40K sphx_glr_plot_adapt_rgb_thumb.png
 26K sphx_glr_plot_attribute_operators_thumb.png
 51K sphx_glr_plot_blob_thumb.png
 83K sphx_glr_plot_boundary_merge_thumb.png
 44K sphx_glr_plot_brief_thumb.png
 25K sphx_glr_plot_camera_numpy_thumb.png
 20K sphx_glr_plot_canny_thumb.png
 46K sphx_glr_plot_censure_thumb.png
 30K sphx_glr_plot_chan_vese_thumb.png
 27K sphx_glr_plot_circular_elliptical_hough_transform_thumb.png
 21K sphx_glr_plot_coins_segmentation_thumb.png
 42K sphx_glr_plot_compact_watershed_thumb.png
 26K sphx_glr_plot_contours_thumb.png
9,6K sphx_glr_plot_convex_hull_thumb.png
 14K sphx_glr_plot_corner_thumb.png
 37K sphx_glr_plot_cycle_spinning_thumb.png
 56K sphx_glr_plot_daisy_thumb.png
 41K sphx_glr_plot_deconvolution_thumb.png
 48K sphx_glr_plot_denoise_thumb.png
 11K sphx_glr_plot_denoise_wavelet_thumb.png
 50K sphx_glr_plot_dog_thumb.png
 37K sphx_glr_plot_edge_filter_thumb.png
 12K sphx_glr_plot_edge_modes_thumb.png
 37K sphx_glr_plot_entropy_thumb.png
 34K sphx_glr_plot_equalize_thumb.png
 25K sphx_glr_plot_extrema_thumb.png
 51K sphx_glr_plot_face_detection_thumb.png
6,6K sphx_glr_plot_floodfill_thumb.png
 33K sphx_glr_plot_fundamental_matrix_thumb.png
 42K sphx_glr_plot_gabors_from_astronaut_thumb.png
 30K sphx_glr_plot_gabor_thumb.png
 55K sphx_glr_plot_general_thumb.png
 31K sphx_glr_plot_geometric_thumb.png
 24K sphx_glr_plot_glcm_thumb.png
 22K sphx_glr_plot_haar_extraction_selection_classification_thumb.png
7,8K sphx_glr_plot_haar_thumb.png
 40K sphx_glr_plot_histogram_matching_thumb.png
 46K sphx_glr_plot_hog_thumb.png
 24K sphx_glr_plot_holes_and_peaks_thumb.png
 62K sphx_glr_plot_hysteresis_thumb.png
 67K sphx_glr_plot_ihc_color_separation_thumb.png
 44K sphx_glr_plot_image_comparison_thumb.png
 43K sphx_glr_plot_inpaint_thumb.png
 46K sphx_glr_plot_join_segmentations_thumb.png
 50K sphx_glr_plot_label_thumb.png
7,5K sphx_glr_plot_line_hough_transform_thumb.png
8,6K sphx_glr_plot_local_binary_pattern_thumb.png
 38K sphx_glr_plot_local_equalize_thumb.png
 26K sphx_glr_plot_log_gamma_thumb.png
 40K sphx_glr_plot_marching_cubes_thumb.png
 46K sphx_glr_plot_marked_watershed_thumb.png
 23K sphx_glr_plot_masked_register_translation_thumb.png
 38K sphx_glr_plot_matching_thumb.png
 13K sphx_glr_plot_max_tree_thumb.png
 55K sphx_glr_plot_metrics_thumb.png
 13K sphx_glr_plot_morphology_thumb.png
 50K sphx_glr_plot_morphsnakes_thumb.png
 43K sphx_glr_plot_multiblock_local_binary_pattern_thumb.png
 19K sphx_glr_plot_multiotsu_thumb.png
 30K sphx_glr_plot_ncut_thumb.png
 23K sphx_glr_plot_niblack_sauvola_thumb.png
 65K sphx_glr_plot_nonlocal_means_thumb.png
 37K sphx_glr_plot_opticalflow_thumb.png
 50K sphx_glr_plot_orb_thumb.png
 31K sphx_glr_plot_peak_local_max_thumb.png
 35K sphx_glr_plot_phase_unwrap_thumb.png
 55K sphx_glr_plot_piecewise_affine_thumb.png
 15K sphx_glr_plot_polygon_thumb.png
 59K sphx_glr_plot_pyramid_thumb.png
 26K sphx_glr_plot_radon_transform_thumb.png
 66K sphx_glr_plot_rag_boundary_thumb.png
 62K sphx_glr_plot_rag_draw_thumb.png
 31K sphx_glr_plot_rag_mean_color_thumb.png
 39K sphx_glr_plot_rag_merge_thumb.png
 15K sphx_glr_plot_rag_thumb.png
 16K sphx_glr_plot_random_shapes_thumb.png
 54K sphx_glr_plot_random_walker_segmentation_thumb.png
 27K sphx_glr_plot_rank_filters_thumb.png
 33K sphx_glr_plot_rank_mean_thumb.png
 16K sphx_glr_plot_ransac_thumb.png
 25K sphx_glr_plot_regional_maxima_thumb.png
 17K sphx_glr_plot_regionprops_table_thumb.png
8,3K sphx_glr_plot_regionprops_thumb.png
 34K sphx_glr_plot_register_rotation_thumb.png
 22K sphx_glr_plot_register_translation_thumb.png
 50K sphx_glr_plot_rescale_thumb.png
 47K sphx_glr_plot_restoration_thumb.png
 59K sphx_glr_plot_rgb_to_gray_thumb.png
 35K sphx_glr_plot_rgb_to_hsv_thumb.png
 62K sphx_glr_plot_ridge_filter_thumb.png
 62K sphx_glr_plot_scientific_thumb.png
 90K sphx_glr_plot_segmentations_thumb.png
 45K sphx_glr_plot_shape_index_thumb.png
8,7K sphx_glr_plot_shapes_thumb.png
 11K sphx_glr_plot_skeleton_thumb.png
 45K sphx_glr_plot_specific_thumb.png
 36K sphx_glr_plot_ssim_thumb.png
 51K sphx_glr_plot_structuring_elements_thumb.png
 13K sphx_glr_plot_swirl_thumb.png
 22K sphx_glr_plot_template_thumb.png
 34K sphx_glr_plot_thresholding_thumb1.png
 16K sphx_glr_plot_thresholding_thumb.png
 19K sphx_glr_plot_threshold_li_thumb.png
 26K sphx_glr_plot_tinting_grayscale_images_thumb.png
 18K sphx_glr_plot_tophat_thumb.png
 22K sphx_glr_plot_transform_types_thumb.png
 35K sphx_glr_plot_unsharp_mask_thumb.png
 50K sphx_glr_plot_view_as_blocks_thumb.png
8,5K sphx_glr_plot_watershed_thumb.png
 46K sphx_glr_plot_windowed_histogram_thumb.png
 37K sphx_glr_plot_window_thumb.png
```


## Result

It appears that we gain another factor 2 on the thumbnail size.

Note that the documentation built duration is significantly increased (several times), I did not quantified. However, in the current version of the patch, it seems to me that the optimization is performed on all png images, not only thumbnails. Limiting the optimization to thumbnails would certainly improve strongly the built duration. Note also that optipng is called with an aggressive optimization (o7).


Discussion:
Very cool @sciunto ! Q: how does the *render time* change? ie is bandwidth the limiting factor? I expect as much but thought I’d ask. If the speed up in load time is also ~2x, I reckon it’s totally worth it. 
The former thumbnail size reduction (~x2) leads to a loading time decrease from 12.8s to 7.9. Not exactly a factor 2, because there is a 1-2 s delay to be at the stage where images are loaded. I believe that the optimization could lead to another reduction of 3 to 5 s.

The transferred data has decreased from 7 to 4 MB. In terms of energy consumption, this is also significant.

Resolving patch:
diff --git a/doc/source/conf.py b/doc/source/conf.py
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -189,6 +189,15 @@
     'remove_config_comments':True,
 }
 
+from sphinx_gallery.utils import _has_optipng
+if _has_optipng():
+    # This option requires optipng to compress images
+    # Optimization level between 0-7
+    # sphinx-gallery default: -o7
+    # optipng default: -o2
+    # We choose -o1 as it produces a sufficient optimization
+    # See #4800
+    sphinx_gallery_conf['compress_images'] = ('images', 'thumbnails', '-o1')
 
 
 # -- Options for HTML output ---------------------------------------------------


Test patch: