Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: chrome/utility/media_galleries/image_metadata_extractor.cc

Issue 191583002: Media Galleries API Metadata: Image metadata (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/utility/media_galleries/image_metadata_extractor.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "media/base/data_source.h"
13 #include "net/base/io_buffer.h"
14
15 extern "C" {
16 #include <libexif/exif-data.h>
17 } // extern "C"
18
19 namespace metadata {
20
21 namespace {
22
23 const int kMaxBufferSize = 50 * 1024 * 1024; // Arbitrary maximum of 50MB.
24
25 void FinishGetImageBytes(
26 net::DrainableIOBuffer* buffer,
27 media::DataSource* source,
28 const base::Callback<void(net::DrainableIOBuffer*)>& callback,
29 int bytes_read) {
30 if (media::DataSource::kReadError == bytes_read) {
Lei Zhang 2014/03/11 23:38:43 bytes_read == media::DataSource::kReadError
tommycli 2014/03/12 00:09:05 Done.
31 callback.Run(NULL);
32 return;
33 }
34
35 buffer->DidConsume(bytes_read);
36 // Didn't get the whole file. Continue reading to get the rest.
37 if (buffer->BytesRemaining() > 0) {
38 source->Read(0, buffer->BytesRemaining(), (uint8*)buffer->data(),
39 base::Bind(&FinishGetImageBytes, make_scoped_refptr(buffer),
40 base::Unretained(source), callback));
41 return;
42 }
43
44 buffer->SetOffset(0);
45 callback.Run(make_scoped_refptr(buffer));
46 }
47
48 void GetImageBytes(
49 media::DataSource* source,
50 const base::Callback<void(net::DrainableIOBuffer*)>& callback) {
51 int64 size64 = 0;
52 if (!source->GetSize(&size64) || size64 > kMaxBufferSize)
53 return callback.Run(NULL);
54 int size = base::checked_cast<int>(size64);
55
56 scoped_refptr<net::DrainableIOBuffer> buffer(
57 new net::DrainableIOBuffer(new net::IOBuffer(size), size));
58 source->Read(0, buffer->BytesRemaining(), (uint8*)buffer->data(),
59 base::Bind(&FinishGetImageBytes, buffer,
60 base::Unretained(source), callback));
61 }
62
63 void ExtractInt(ExifData* data, ExifTag tag, int* result) {
64 DCHECK(result);
65
66 ExifEntry* entry = exif_data_get_entry(data, tag);
67
68 if (entry) {
69 ExifByteOrder order = exif_data_get_byte_order(data);
70
71 switch (entry->format) {
Lei Zhang 2014/03/11 23:38:43 Just DCHECK_EQ(EXIF_FORMAT_SHORT, entry->format) a
tommycli 2014/03/12 00:09:05 I don't want to actually crash if the ExifEntry is
Lei Zhang 2014/03/12 01:55:29 Is your concern that the NOTREACHED() case will ac
tommycli 2014/03/12 16:27:48 Oh you're right. I made a mistake. I realized I al
72 case EXIF_FORMAT_SHORT: {
73 ExifShort v = exif_get_short(entry->data, order);
74 *result = base::checked_cast<int>(v);
75 break;
76 }
77 default: {
78 NOTREACHED();
79 }
80 }
81 }
82 }
83
84 void ExtractDouble(ExifData* data, ExifTag tag, double* result) {
85 DCHECK(result);
86
87 ExifEntry* entry = exif_data_get_entry(data, tag);
88
89 if (entry) {
90 ExifByteOrder order = exif_data_get_byte_order(data);
91
92 switch (entry->format) {
93 case EXIF_FORMAT_RATIONAL: {
94 ExifRational v = exif_get_rational(entry->data, order);
95 *result = base::checked_cast<double>(v.numerator) /
96 base::checked_cast<double>(v.denominator);
97 break;
98 }
99 default: {
100 NOTREACHED();
101 }
102 }
103 }
104 }
105
106 void ExtractString(ExifData* data, ExifTag tag, std::string* result) {
107 DCHECK(result);
108
109 ExifEntry* entry = exif_data_get_entry(data, tag);
110
111 if (entry) {
112 char buf[1024];
113 exif_entry_get_value(entry, buf, sizeof(buf));
114 *result = buf;
115 }
116 }
117
118 } // namespace
119
120 ImageMetadataExtractor::ImageMetadataExtractor()
121 : extracted_(false),
122 width_(-1),
123 height_(-1),
124 rotation_(-1),
125 x_resolution_(-1),
126 y_resolution_(-1),
127 exposure_time_sec_(-1),
128 flash_fired_(false),
129 f_number_(-1),
130 focal_length_mm_(-1),
131 iso_equivalent_(-1) {
132 }
133
134 ImageMetadataExtractor::~ImageMetadataExtractor() {
135 }
136
137 void ImageMetadataExtractor::Extract(media::DataSource* source,
138 const DoneCallback& callback) {
139 DCHECK(!extracted_);
140
141 GetImageBytes(source, base::Bind(&ImageMetadataExtractor::FinishExtraction,
142 base::Unretained(this), callback));
143
144 }
145
146 int ImageMetadataExtractor::width() const {
147 DCHECK(extracted_);
148 return width_;
149 }
150
151 int ImageMetadataExtractor::height() const {
152 DCHECK(extracted_);
153 return height_;
154 }
155
156 int ImageMetadataExtractor::rotation() const {
157 DCHECK(extracted_);
158 return rotation_;
159 }
160
161 double ImageMetadataExtractor::x_resolution() const {
162 DCHECK(extracted_);
163 return x_resolution_;
164 }
165
166 double ImageMetadataExtractor::y_resolution() const {
167 DCHECK(extracted_);
168 return y_resolution_;
169 }
170
171 const std::string& ImageMetadataExtractor::date() const {
172 DCHECK(extracted_);
173 return date_;
174 }
175
176 const std::string& ImageMetadataExtractor::camera_make() const {
177 DCHECK(extracted_);
178 return camera_make_;
179 }
180
181 const std::string& ImageMetadataExtractor::camera_model() const {
182 DCHECK(extracted_);
183 return camera_model_;
184 }
185
186 double ImageMetadataExtractor::exposure_time_sec() const {
187 DCHECK(extracted_);
188 return exposure_time_sec_;
189 }
190
191 bool ImageMetadataExtractor::flash_fired() const {
192 DCHECK(extracted_);
193 return flash_fired_;
194 }
195
196 double ImageMetadataExtractor::f_number() const {
197 DCHECK(extracted_);
198 return f_number_;
199 }
200
201 double ImageMetadataExtractor::focal_length_mm() const {
202 DCHECK(extracted_);
203 return focal_length_mm_;
204 }
205
206 int ImageMetadataExtractor::iso_equivalent() const {
207 DCHECK(extracted_);
208 return iso_equivalent_;
209 }
210
211 void ImageMetadataExtractor::FinishExtraction(
212 const DoneCallback& callback, net::DrainableIOBuffer* buffer) {
213 if (!buffer) {
214 callback.Run(false);
215 return;
216 }
217
218 ExifData* data = exif_data_new_from_data(
219 (unsigned char*)buffer->data(), buffer->BytesRemaining());
220
221 if (!data) {
222 callback.Run(false);
223 return;
224 }
225
226 ExtractInt(data, EXIF_TAG_IMAGE_WIDTH, &width_);
227 ExtractInt(data, EXIF_TAG_IMAGE_LENGTH, &height_);
228
229 // We ignore the mirrored-aspect of the mirrored-orientations and just
230 // indicate the rotation. Mirrored-orientations are very rare.
231 int orientation = 0;
232 ExtractInt(data, EXIF_TAG_ORIENTATION, &orientation);
233 switch (orientation) {
234 case 1:
235 case 2:
236 rotation_ = 0;
237 break;
238 case 3:
239 case 4:
240 rotation_ = 180;
241 break;
242 case 5:
243 case 6:
244 rotation_ = 90;
245 break;
246 case 7:
247 case 8:
248 rotation_ = 270;
249 break;
250 }
251
252 ExtractDouble(data, EXIF_TAG_X_RESOLUTION, &x_resolution_);
253 ExtractDouble(data, EXIF_TAG_Y_RESOLUTION, &y_resolution_);
254
255 ExtractString(data, EXIF_TAG_DATE_TIME, &date_);
256
257 ExtractString(data, EXIF_TAG_MAKE, &camera_make_);
258 ExtractString(data, EXIF_TAG_MODEL, &camera_model_);
259 ExtractDouble(data, EXIF_TAG_EXPOSURE_TIME, &exposure_time_sec_);
260
261 int flash_value = -1;
262 ExtractInt(data, EXIF_TAG_FLASH, &flash_value);
263 if (flash_value >= 0) {
264 flash_fired_ = (flash_value & 0x1) != 0;
265 }
266
267 ExtractDouble(data, EXIF_TAG_FNUMBER, &f_number_);
268 ExtractDouble(data, EXIF_TAG_FOCAL_LENGTH, &focal_length_mm_);
269 ExtractInt(data, EXIF_TAG_ISO_SPEED_RATINGS, &iso_equivalent_);
270
271 exif_data_free(data);
272
273 extracted_ = true;
274
275 callback.Run(true);
276 }
277
278 } // namespace metadata
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698