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

Side by Side Diff: ui/gfx/color_utils.cc

Issue 12335009: Implementation of principal-component color reduction. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed (some) remarks from the review. Created 7 years, 10 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/color_utils.h" 5 #include "ui/gfx/color_utils.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 #if defined(OS_WIN) 8 #if defined(OS_WIN)
9 #include <windows.h> 9 #include <windows.h>
10 #endif 10 #endif
11 11
12 #include <algorithm> 12 #include <algorithm>
13 #include <limits>
13 14
14 #include "base/basictypes.h" 15 #include "base/basictypes.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "build/build_config.h" 17 #include "build/build_config.h"
17 #if defined(OS_WIN) 18 #if defined(OS_WIN)
18 #include "skia/ext/skia_utils_win.h" 19 #include "skia/ext/skia_utils_win.h"
19 #endif 20 #endif
20 #include "third_party/skia/include/core/SkBitmap.h" 21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "third_party/skia/include/core/SkUnPreMultiply.h"
23 #include "ui/gfx/color_analysis.h"
24 #include "ui/gfx/matrix3_f.h"
25 #include "ui/gfx/vector3d_f.h"
21 26
22 namespace color_utils { 27 namespace color_utils {
23 28
24 // Helper functions ----------------------------------------------------------- 29 // Helper functions -----------------------------------------------------------
25 30
26 namespace { 31 namespace {
27 32
28 int calcHue(double temp1, double temp2, double hue) { 33 int calcHue(double temp1, double temp2, double hue) {
29 if (hue < 0.0) 34 if (hue < 0.0)
30 ++hue; 35 ++hue;
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 259
255 SkColor GetSysSkColor(int which) { 260 SkColor GetSysSkColor(int which) {
256 #if defined(OS_WIN) 261 #if defined(OS_WIN)
257 return skia::COLORREFToSkColor(GetSysColor(which)); 262 return skia::COLORREFToSkColor(GetSysColor(which));
258 #else 263 #else
259 NOTIMPLEMENTED(); 264 NOTIMPLEMENTED();
260 return SK_ColorLTGRAY; 265 return SK_ColorLTGRAY;
261 #endif 266 #endif
262 } 267 }
263 268
269 bool ApplyColorReduction(const SkBitmap& source_bitmap,
270 const gfx::Vector3dF& color_transform,
271 bool scale_result,
272 SkBitmap* target_bitmap) {
273 if (!target_bitmap) {
Alexei Svitkine (slow) 2013/02/21 19:49:33 Do you really need all these early returns? Can yo
motek. 2013/02/21 22:45:03 I think I borrowed this idiom from somewhere. Like
274 NOTREACHED();
275 return false;
276 }
277
278 SkAutoLockPixels source_lock(source_bitmap);
279 SkAutoLockPixels target_lock(*target_bitmap);
280
281 if (!source_bitmap.getPixels())
282 return false;
283
284 if (!target_bitmap->getPixels()) {
285 NOTREACHED();
286 return false;
287 }
288
289 DCHECK(source_bitmap.config() == SkBitmap::kARGB_8888_Config);
290 DCHECK(target_bitmap->config() == SkBitmap::kA8_Config);
291 DCHECK_EQ(source_bitmap.height(), target_bitmap->height());
292 DCHECK_EQ(source_bitmap.width(), target_bitmap->width());
293
294 int height = std::min(source_bitmap.height(), target_bitmap->height());
295 int width = std::min(source_bitmap.width(), target_bitmap->width());
296 DCHECK(height > 0 && width > 0);
297
298 float a0 = 0.0;
299 float scale = 1.0;
300 if (scale_result) {
Alexei Svitkine (slow) 2013/02/21 19:49:33 I think it would be cleaner to do the scaling in a
motek. 2013/02/21 22:45:03 I don't really follow. To know how to scale I need
Alexei Svitkine (slow) 2013/02/22 02:24:06 Ah, you're right, I didn't realise we couldn't re-
301 // We will figure out min/max in a preprocessing step and adjust
302 // actual_transform as required.
303 float max_val = std::numeric_limits<float>::min();
304 float min_val = std::numeric_limits<float>::max();
305 for (int y = 0; y < height; ++y) {
306 SkPMColor* current_color = static_cast<uint32_t*>(
Alexei Svitkine (slow) 2013/02/21 19:49:33 Should this be a static_cast<SkPMColor*>?
motek. 2013/02/21 22:45:03 Seems you are right. Done.
307 source_bitmap.getAddr32(0, y));
308 for (int x = 0; x < width; ++x, ++current_color) {
309 SkColor c = SkUnPreMultiply::PMColorToColor(*current_color);
310 float r = SkColorGetR(c);
311 float g = SkColorGetG(c);
312 float b = SkColorGetB(c);
313 float gray_level = gfx::DotProduct(color_transform, r, g, b);
314 max_val = std::max(max_val, gray_level);
315 min_val = std::min(min_val, gray_level);
316 }
317 }
318
319 // Adjust the transform so that the result is scalling.
320 a0 = -min_val;
321 if (max_val > min_val)
322 scale = 255.0 / (max_val - min_val);
323 else
324 scale = 0.0; // If min==max, uniform 0-level image is expected.
325 }
326
327 for (int y = 0; y < height; ++y) {
328 SkPMColor* current_color = static_cast<uint32_t*>(
Alexei Svitkine (slow) 2013/02/21 19:49:33 Likewise, cast to SkPMColor*?
motek. 2013/02/21 22:45:03 Done.
329 source_bitmap.getAddr32(0, y));
330 uint8_t* target_color = target_bitmap->getAddr8(0, y);
331 for (int x = 0; x < width; ++x, ++current_color) {
332 SkColor c = SkUnPreMultiply::PMColorToColor(*current_color);
333 float r = SkColorGetR(c);
334 float g = SkColorGetG(c);
335 float b = SkColorGetB(c);
336
337 float gl = (a0 + gfx::DotProduct(color_transform, r, g, b)) * scale;
338 if (gl < 0)
339 gl = 0;
340 if (gl > 0xFF)
341 gl = 0xFF;
342 target_color[x] = static_cast<uint8_t>(gl);
343 }
344 }
345
346 return true;
347 }
348
349 bool ComputePrincipalComponentImage(const SkBitmap& source_bitmap,
350 SkBitmap* target_bitmap) {
351 if (!target_bitmap) {
352 NOTREACHED();
353 return false;
354 }
355
356 gfx::Matrix3F covariance = ComputeColorCovariance(source_bitmap);
357 gfx::Matrix3F eigenvectors = gfx::Matrix3F::Zeros();
358 gfx::Vector3dF eigenvals = covariance.SolveEigenproblem(&eigenvectors);
359 gfx::Vector3dF principal = eigenvectors.get_column(0);
360 if (eigenvals == gfx::Vector3dF() || principal == gfx::Vector3dF())
361 return false; // This may happen for some edge cases.
362 return ApplyColorReduction(source_bitmap, principal, true, target_bitmap);
363 }
364
264 } // namespace color_utils 365 } // namespace color_utils
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698