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

Side by Side Diff: src/core/SkDistanceFieldGen.cpp

Issue 197423003: Fix distance field edge detection. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address nits 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkDistanceFieldGen.h" 8 #include "SkDistanceFieldGen.h"
9 #include "SkPoint.h" 9 #include "SkPoint.h"
10 10
11 struct DFData { 11 struct DFData {
12 float fAlpha; // alpha value of source texel 12 float fAlpha; // alpha value of source texel
13 float fDistSq; // distance squared to nearest (so far) edge texel 13 float fDistSq; // distance squared to nearest (so far) edge texel
14 SkPoint fDistVector; // distance vector to nearest (so far) edge texel 14 SkPoint fDistVector; // distance vector to nearest (so far) edge texel
15 }; 15 };
16 16
17 enum NeighborFlags {
18 kLeft_NeighborFlag = 0x01,
19 kRight_NeighborFlag = 0x02,
20 kTopLeft_NeighborFlag = 0x04,
21 kTop_NeighborFlag = 0x08,
22 kTopRight_NeighborFlag = 0x10,
23 kBottomLeft_NeighborFlag = 0x20,
24 kBottom_NeighborFlag = 0x40,
25 kBottomRight_NeighborFlag = 0x80,
26 kAll_NeighborFlags = 0xff,
27
28 kNeighborFlagCount = 8
29 };
30
17 // We treat an "edge" as a place where we cross from a texel >= 128 to a texel < 128, 31 // We treat an "edge" as a place where we cross from a texel >= 128 to a texel < 128,
18 // or vice versa. This means we just need to check if the MSBs are different. 32 // or vice versa. This means we just need to check if the MSBs are different.
19 static bool found_edge(const unsigned char* imagePtr, int width) { 33 // 'neighborFlags' is used to limit the directions in which we test to avoid ind exing
34 // outside of the image
35 static bool found_edge(const unsigned char* imagePtr, int width, int neighborFla gs) {
36 // the order of these should match the neighbor flags above
37 const int kNum8ConnectedNeighbors = 8;
20 const int offsets[8] = {-1, 1, -width-1, -width, -width+1, width-1, width, w idth+1 }; 38 const int offsets[8] = {-1, 1, -width-1, -width, -width+1, width-1, width, w idth+1 };
39 SkASSERT(kNum8ConnectedNeighbors == kNeighborFlagCount);
21 40
22 // search for an edge 41 // search for an edge
23 int checkVal = *imagePtr >> 7; 42 unsigned char currVal = *imagePtr >> 7;
24 for (int i = 0; i < 8; ++i) { 43 for (int i = 0; i < kNum8ConnectedNeighbors; ++i) {
25 const unsigned char* checkPtr = imagePtr + offsets[i]; 44 unsigned char checkVal;
26 if (checkVal ^ (*checkPtr >> 7)) { 45 if ((1 << i) & neighborFlags) {
46 const unsigned char* checkPtr = imagePtr + offsets[i];
47 checkVal = *checkPtr >> 7;
48 } else {
49 checkVal = 0;
50 }
51 SkASSERT(checkVal == 0 || checkVal == 1);
52 SkASSERT(currVal == 0 || currVal == 1);
53 if (checkVal != currVal) {
27 return true; 54 return true;
28 } 55 }
29 } 56 }
30 57
31 return false; 58 return false;
32 } 59 }
33 60
34 static void init_glyph_data(DFData* data, unsigned char* edges, const unsigned c har* image, 61 static void init_glyph_data(DFData* data, unsigned char* edges, const unsigned c har* image,
35 int dataWidth, int dataHeight, 62 int dataWidth, int dataHeight,
36 int imageWidth, int imageHeight, 63 int imageWidth, int imageHeight,
37 int pad) { 64 int pad) {
38 data += pad*dataWidth; 65 data += pad*dataWidth;
39 data += pad; 66 data += pad;
40 edges += (pad*dataWidth + pad); 67 edges += (pad*dataWidth + pad);
41 68
42 for (int j = 0; j < imageHeight; ++j) { 69 for (int j = 0; j < imageHeight; ++j) {
43 for (int i = 0; i < imageWidth; ++i) { 70 for (int i = 0; i < imageWidth; ++i) {
44 if (255 == *image) { 71 if (255 == *image) {
45 data->fAlpha = 1.0f; 72 data->fAlpha = 1.0f;
46 } else { 73 } else {
47 data->fAlpha = (*image)*0.00392156862f; // 1/255 74 data->fAlpha = (*image)*0.00392156862f; // 1/255
48 } 75 }
49 if (i > 0 && i < imageWidth-1 && j > 0 && j < imageHeight-1 && 76 int checkMask = kAll_NeighborFlags;
50 found_edge(image, imageWidth)) { 77 if (i == 0) {
78 checkMask &= ~(kLeft_NeighborFlag|kTopLeft_NeighborFlag|kBottomL eft_NeighborFlag);
79 }
80 if (i == imageWidth-1) {
81 checkMask &= ~(kRight_NeighborFlag|kTopRight_NeighborFlag|kBotto mRight_NeighborFlag);
82 }
83 if (j == 0) {
84 checkMask &= ~(kTopLeft_NeighborFlag|kTop_NeighborFlag|kTopRight _NeighborFlag);
85 }
86 if (j == imageHeight-1) {
87 checkMask &= ~(kBottomLeft_NeighborFlag|kBottom_NeighborFlag|kBo ttomRight_NeighborFlag);
88 }
89 if (found_edge(image, imageWidth, checkMask)) {
51 *edges = 255; // using 255 makes for convenient debug rendering 90 *edges = 255; // using 255 makes for convenient debug rendering
52 } 91 }
53 ++data; 92 ++data;
54 ++image; 93 ++image;
55 ++edges; 94 ++edges;
56 } 95 }
57 data += 2*pad; 96 data += 2*pad;
58 edges += 2*pad; 97 edges += 2*pad;
59 } 98 }
60 } 99 }
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 distVec = check->fDistVector; 300 distVec = check->fDistVector;
262 distSq = check->fDistSq + 2.0f*(distVec.fX + distVec.fY + 1.0f); 301 distSq = check->fDistSq + 2.0f*(distVec.fX + distVec.fY + 1.0f);
263 if (distSq < curr->fDistSq) { 302 if (distSq < curr->fDistSq) {
264 distVec.fX += 1.0f; 303 distVec.fX += 1.0f;
265 distVec.fY += 1.0f; 304 distVec.fY += 1.0f;
266 curr->fDistSq = distSq; 305 curr->fDistSq = distSq;
267 curr->fDistVector = distVec; 306 curr->fDistVector = distVec;
268 } 307 }
269 } 308 }
270 309
310 // enable this to output edge data rather than the distance field
311 #define DUMP_EDGE 0
312
313 #if !DUMP_EDGE
271 static unsigned char pack_distance_field_val(float dist, float distanceMagnitude ) { 314 static unsigned char pack_distance_field_val(float dist, float distanceMagnitude ) {
272 if (dist <= -distanceMagnitude) { 315 if (dist <= -distanceMagnitude) {
273 return 255; 316 return 255;
274 } else if (dist > distanceMagnitude) { 317 } else if (dist > distanceMagnitude) {
275 return 0; 318 return 0;
276 } else { 319 } else {
277 return (unsigned char)((distanceMagnitude-dist)*128.0f/distanceMagnitude ); 320 return (unsigned char)((distanceMagnitude-dist)*128.0f/distanceMagnitude );
278 } 321 }
279 } 322 }
323 #endif
280 324
281 // assumes an 8-bit image and distance field 325 // assumes an 8-bit image and distance field
282 bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField, 326 bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField,
283 const unsigned char* image, 327 const unsigned char* image,
284 int width, int height, 328 int width, int height,
285 int distanceMagnitude) { 329 int distanceMagnitude) {
286 SkASSERT(NULL != distanceField); 330 SkASSERT(NULL != distanceField);
287 SkASSERT(NULL != image); 331 SkASSERT(NULL != image);
288 332
289 // the final distance field will have additional texels on each side to hand le 333 // the final distance field will have additional texels on each side to hand le
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 currData -= dataWidth-1; 419 currData -= dataWidth-1;
376 currEdge -= dataWidth-1; 420 currEdge -= dataWidth-1;
377 } 421 }
378 422
379 // copy results to final distance field data 423 // copy results to final distance field data
380 currData = dataPtr + dataWidth+1; 424 currData = dataPtr + dataWidth+1;
381 currEdge = edgePtr + dataWidth+1; 425 currEdge = edgePtr + dataWidth+1;
382 unsigned char *dfPtr = distanceField; 426 unsigned char *dfPtr = distanceField;
383 for (int j = 1; j < dataHeight-1; ++j) { 427 for (int j = 1; j < dataHeight-1; ++j) {
384 for (int i = 1; i < dataWidth-1; ++i) { 428 for (int i = 1; i < dataWidth-1; ++i) {
429 #if DUMP_EDGE
430 unsigned char val = (currData->fAlpha >= 0.5f) ? 255 : 0;
431 if (*currEdge) {
432 val = 128;
433 }
434 *dfPtr++ = val;
435 #else
385 float dist; 436 float dist;
386 if (currData->fAlpha > 0.5f) { 437 if (currData->fAlpha > 0.5f) {
387 dist = -SkScalarSqrt(currData->fDistSq); 438 dist = -SkScalarSqrt(currData->fDistSq);
388 } else { 439 } else {
389 dist = SkScalarSqrt(currData->fDistSq); 440 dist = SkScalarSqrt(currData->fDistSq);
390 } 441 }
391
392 *dfPtr++ = pack_distance_field_val(dist, (float)distanceMagnitude); 442 *dfPtr++ = pack_distance_field_val(dist, (float)distanceMagnitude);
443 #endif
393 ++currData; 444 ++currData;
394 ++currEdge; 445 ++currEdge;
395 } 446 }
396 currData += 2; 447 currData += 2;
397 currEdge += 2; 448 currEdge += 2;
398 } 449 }
399 450
400 return true; 451 return true;
401 } 452 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698