Photo Gallery by Envira – Responsive Image Gallery for WordPress - Version 1.3.5.2

Version Description

  • Fix: Correct image orientation for uploaded images (whether through Envira or not). Fixes known issue: https://core.trac.wordpress.org/ticket/14459
Download this release

Release Info

Developer n7studios
Plugin Icon 128x128 Photo Gallery by Envira – Responsive Image Gallery for WordPress
Version 1.3.5.2
Comparing to
See all releases

Code changes from version 1.3.5.1 to 1.3.5.2

Files changed (3) hide show
  1. envira-gallery-lite.php +2 -2
  2. includes/admin/media.php +225 -0
  3. readme.txt +3 -0
envira-gallery-lite.php CHANGED
@@ -5,7 +5,7 @@
5
  * Description: Envira Gallery is best responsive WordPress gallery plugin. This is the lite version.
6
  * Author: Thomas Griffin
7
  * Author URI: http://thomasgriffinmedia.com
8
- * Version: 1.3.5.1
9
  * Text Domain: envira-gallery-lite
10
  *
11
  * Envira Gallery is free software: you can redistribute it and/or modify
@@ -53,7 +53,7 @@ class Envira_Gallery_Lite {
53
  *
54
  * @var string
55
  */
56
- public $version = '1.3.5.1';
57
 
58
  /**
59
  * Unique plugin slug identifier.
5
  * Description: Envira Gallery is best responsive WordPress gallery plugin. This is the lite version.
6
  * Author: Thomas Griffin
7
  * Author URI: http://thomasgriffinmedia.com
8
+ * Version: 1.3.5.2
9
  * Text Domain: envira-gallery-lite
10
  *
11
  * Envira Gallery is free software: you can redistribute it and/or modify
53
  *
54
  * @var string
55
  */
56
+ public $version = '1.3.5.2';
57
 
58
  /**
59
  * Unique plugin slug identifier.
includes/admin/media.php CHANGED
@@ -46,6 +46,231 @@ class Envira_Gallery_Media_Lite {
46
  // Load the base class object.
47
  $this->base = Envira_Gallery_Lite::get_instance();
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
 
51
  /**
46
  // Load the base class object.
47
  $this->base = Envira_Gallery_Lite::get_instance();
48
 
49
+ add_filter( 'wp_handle_upload', array( $this, 'fix_image_orientation' ) );
50
+
51
+ }
52
+
53
+ /**
54
+ * Check if the EXIF orientation flag matches one of the values we're looking for
55
+ * http://www.impulseadventure.com/photo/exif-orientation.html
56
+ *
57
+ * If it does, this means we need to rotate the image based on the orientation flag and then remove the flag.
58
+ * This will ensure the image has the correct orientation, regardless of where it's displayed.
59
+ *
60
+ * Whilst most browsers and applications will read this flag to perform the rotation on displaying just the image, it's
61
+ * not possible to do this in some situations e.g. displaying an image within a lightbox, or when the image is
62
+ * within HTML markup.
63
+ *
64
+ * Orientation flags we're looking for:
65
+ * 8: We need to rotate the image 90 degrees counter-clockwise
66
+ * 3: We need to rotate the image 180 degrees
67
+ * 6: We need to rotate the image 90 degrees clockwise (270 degrees counter-clockwise)
68
+ *
69
+ * @since 1.3.8.2
70
+ *
71
+ * @param array $file Uploaded File
72
+ * @return array Uploaded File
73
+ */
74
+ public function fix_image_orientation( $file ) {
75
+
76
+ // Check we have a file
77
+ if ( ! file_exists( $file['file'] ) ) {
78
+ return $file;
79
+ }
80
+
81
+ // Check we have a JPEG
82
+ if ( $file['type'] !== 'image/jpg' && $file['type'] !== 'image/jpeg' ) {
83
+ return $file;
84
+ }
85
+
86
+ // Attempt to read EXIF data from the image
87
+ $exif_data = wp_read_image_metadata( $file['file'] );
88
+ if ( ! $exif_data ) {
89
+ return $file;
90
+ }
91
+
92
+ // Check if an orientation flag exists
93
+ if ( ! isset( $exif_data['orientation'] ) ) {
94
+ return $file;
95
+ }
96
+
97
+ // Check if the orientation flag matches one we're looking for
98
+ $required_orientations = array( 8, 3, 6 );
99
+ if ( ! in_array( $exif_data['orientation'], $required_orientations ) ) {
100
+ return $file;
101
+ }
102
+
103
+ // If here, the orientation flag matches one we're looking for
104
+ // Load the WordPress Image Editor class
105
+ $image = wp_get_image_editor( $file['file'] );
106
+ if ( is_wp_error( $image ) ) {
107
+ // Something went wrong - abort
108
+ return $file;
109
+ }
110
+
111
+ // Store the source image EXIF and IPTC data in a variable, which we'll write
112
+ // back to the image once its orientation has changed
113
+ // This is required because when we save an image, it'll lose its metadata.
114
+ $source_size = getimagesize( $file['file'], $image_info );
115
+
116
+ // Depending on the orientation flag, rotate the image
117
+ switch ( $exif_data['orientation'] ) {
118
+
119
+ /**
120
+ * Rotate 90 degrees counter-clockwise
121
+ */
122
+ case 8:
123
+ $image->rotate( 90 );
124
+ break;
125
+
126
+ /**
127
+ * Rotate 180 degrees
128
+ */
129
+ case 3:
130
+ $image->rotate( 180 );
131
+ break;
132
+
133
+ /**
134
+ * Rotate 270 degrees counter-clockwise ($image->rotate always works counter-clockwise)
135
+ */
136
+ case 6:
137
+ $image->rotate( 270 );
138
+ break;
139
+
140
+ }
141
+
142
+ // Save the image, overwriting the existing image
143
+ // This will discard the EXIF and IPTC data
144
+ $image->save( $file['file'] );
145
+
146
+ // Drop the EXIF orientation flag, otherwise applications will try to rotate the image
147
+ // before display it, and we don't need that to happen as we've corrected the orientation
148
+
149
+ // Write the EXIF and IPTC metadata to the revised image
150
+ $result = $this->transfer_iptc_exif_to_image( $image_info, $file['file'], $exif_data['orientation'] );
151
+ if ( ! $result ) {
152
+ return $file;
153
+ }
154
+
155
+ // Read the image again to see if the EXIF data was preserved
156
+ $exif_data = wp_read_image_metadata( $file['file'] );
157
+
158
+ // Finally, return the data that's expected
159
+ return $file;
160
+
161
+ }
162
+
163
+ /**
164
+ * Transfers IPTC and EXIF data from a source image which contains either/both,
165
+ * and saves it into a destination image's headers that might not have this IPTC
166
+ * or EXIF data
167
+ *
168
+ * Useful for when you edit an image through PHP and need to preserve IPTC and EXIF
169
+ * data
170
+ *
171
+ * @since 1.3.8.2
172
+ *
173
+ * @source http://php.net/iptcembed - ebashkoff at gmail dot com
174
+ *
175
+ * @param string $image_info EXIF and IPTC image information from the source image, using getimagesize()
176
+ * @param string $destination_image Path and File of Destination Image, which needs IPTC and EXIF data
177
+ * @param int $original_orientation The image's original orientation, before we changed it.
178
+ * Used when we replace this orientation in the EXIF data
179
+ * @return bool Success
180
+ */
181
+ private function transfer_iptc_exif_to_image( $image_info, $destination_image, $original_orientation ) {
182
+
183
+ // Check destination exists
184
+ if ( ! file_exists( $destination_image ) ) {
185
+ return false;
186
+ }
187
+
188
+ // Get EXIF data from the image info, and create the IPTC segment
189
+ $exif_data = ( ( is_array( $image_info ) && key_exists( 'APP1', $image_info ) ) ? $image_info['APP1'] : null );
190
+ if ( $exif_data ) {
191
+ // Find the image's original orientation flag, and change it to 1
192
+ // This prevents applications and browsers re-rotating the image, when we've already performed that function
193
+ $exif_data = str_replace( chr( dechex( $original_orientation ) ) , chr( 0x1 ), $exif_data );
194
+
195
+ $exif_length = strlen( $exif_data ) + 2;
196
+ if ( $exif_length > 0xFFFF ) {
197
+ return false;
198
+ }
199
+
200
+ // Construct EXIF segment
201
+ $exif_data = chr(0xFF) . chr(0xE1) . chr( ( $exif_length >> 8 ) & 0xFF) . chr( $exif_length & 0xFF ) . $exif_data;
202
+ }
203
+
204
+ // Get IPTC data from the source image, and create the IPTC segment
205
+ $iptc_data = ( ( is_array( $image_info ) && key_exists( 'APP13', $image_info ) ) ? $image_info['APP13'] : null );
206
+ if ( $iptc_data ) {
207
+ $iptc_length = strlen( $iptc_data ) + 2;
208
+ if ( $iptc_length > 0xFFFF ) {
209
+ return false;
210
+ }
211
+
212
+ // Construct IPTC segment
213
+ $iptc_data = chr(0xFF) . chr(0xED) . chr( ( $iptc_length >> 8) & 0xFF) . chr( $iptc_length & 0xFF ) . $iptc_data;
214
+ }
215
+
216
+ // Get the contents of the destination image
217
+ $destination_image_contents = file_get_contents( $destination_image );
218
+ if ( ! $destination_image_contents ) {
219
+ return false;
220
+ }
221
+ if ( strlen( $destination_image_contents ) == 0 ) {
222
+ return false;
223
+ }
224
+
225
+ // Build the EXIF and IPTC data headers
226
+ $destination_image_contents = substr( $destination_image_contents, 2 );
227
+ $portion_to_add = chr(0xFF) . chr(0xD8); // Variable accumulates new & original IPTC application segments
228
+ $exif_added = ! $exif_data;
229
+ $iptc_added = ! $iptc_data;
230
+
231
+ while ( ( substr( $destination_image_contents, 0, 2 ) & 0xFFF0 ) === 0xFFE0 ) {
232
+ $segment_length = ( substr( $destination_image_contents, 2, 2 ) & 0xFFFF );
233
+ $iptc_segment_number = ( substr( $destination_image_contents, 1, 1 ) & 0x0F ); // Last 4 bits of second byte is IPTC segment #
234
+ if ( $segment_length <= 2 ) {
235
+ return false;
236
+ }
237
+
238
+ $thisexistingsegment = substr( $destination_image_contents, 0, $segment_length + 2 );
239
+ if ( ( 1 <= $iptc_segment_number) && ( ! $exif_added ) ) {
240
+ $portion_to_add .= $exif_data;
241
+ $exif_added = true;
242
+ if ( 1 === $iptc_segment_number ) {
243
+ $thisexistingsegment = '';
244
+ }
245
+ }
246
+
247
+ if ( ( 13 <= $iptc_segment_number ) && ( ! $iptc_added ) ) {
248
+ $portion_to_add .= $iptc_data;
249
+ $iptc_added = true;
250
+ if ( 13 === $iptc_segment_number ) {
251
+ $thisexistingsegment = '';
252
+ }
253
+ }
254
+
255
+ $portion_to_add .= $thisexistingsegment;
256
+ $destination_image_contents = substr( $destination_image_contents, $segment_length + 2 );
257
+ }
258
+
259
+ // Write the EXIF and IPTC data to the new file
260
+ if ( ! $exif_added ) {
261
+ $portion_to_add .= $exif_data;
262
+ }
263
+ if ( ! $iptc_added ) {
264
+ $portion_to_add .= $iptc_data;
265
+ }
266
+
267
+ $output_file = fopen( $destination_image, 'w' );
268
+ if ( $output_file ) {
269
+ return fwrite( $output_file, $portion_to_add . $destination_image_contents );
270
+ }
271
+
272
+ return false;
273
+
274
  }
275
 
276
  /**
readme.txt CHANGED
@@ -57,6 +57,9 @@ Also, I'm an <a href="https://thomasgriffin.io" rel="me" title="WordPress Develo
57
 
58
  == Changelog ==
59
 
 
 
 
60
  = 1.3.5.1 =
61
  * Fix: Gallery shortcodes using slugs working with WordPress 4.3+
62
 
57
 
58
  == Changelog ==
59
 
60
+ = 1.3.5.2 =
61
+ * Fix: Correct image orientation for uploaded images (whether through Envira or not). Fixes known issue: https://core.trac.wordpress.org/ticket/14459
62
+
63
  = 1.3.5.1 =
64
  * Fix: Gallery shortcodes using slugs working with WordPress 4.3+
65