| OLD | NEW |
| 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 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 kTop_NeighborFlag = 0x08, | 21 kTop_NeighborFlag = 0x08, |
| 22 kTopRight_NeighborFlag = 0x10, | 22 kTopRight_NeighborFlag = 0x10, |
| 23 kBottomLeft_NeighborFlag = 0x20, | 23 kBottomLeft_NeighborFlag = 0x20, |
| 24 kBottom_NeighborFlag = 0x40, | 24 kBottom_NeighborFlag = 0x40, |
| 25 kBottomRight_NeighborFlag = 0x80, | 25 kBottomRight_NeighborFlag = 0x80, |
| 26 kAll_NeighborFlags = 0xff, | 26 kAll_NeighborFlags = 0xff, |
| 27 | 27 |
| 28 kNeighborFlagCount = 8 | 28 kNeighborFlagCount = 8 |
| 29 }; | 29 }; |
| 30 | 30 |
| 31 // We treat an "edge" as a place where we cross from black to non-black, or vice
versa. | 31 // We treat an "edge" as a place where we cross from >=128 to <128, or vice vers
a, or |
| 32 // where we have two non-zero pixels that are <128. |
| 32 // 'neighborFlags' is used to limit the directions in which we test to avoid ind
exing | 33 // 'neighborFlags' is used to limit the directions in which we test to avoid ind
exing |
| 33 // outside of the image | 34 // outside of the image |
| 34 static bool found_edge(const unsigned char* imagePtr, int width, int neighborFla
gs) { | 35 static bool found_edge(const unsigned char* imagePtr, int width, int neighborFla
gs) { |
| 35 // the order of these should match the neighbor flags above | 36 // the order of these should match the neighbor flags above |
| 36 const int kNum8ConnectedNeighbors = 8; | 37 const int kNum8ConnectedNeighbors = 8; |
| 37 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 }; |
| 38 SkASSERT(kNum8ConnectedNeighbors == kNeighborFlagCount); | 39 SkASSERT(kNum8ConnectedNeighbors == kNeighborFlagCount); |
| 39 | 40 |
| 40 // search for an edge | 41 // search for an edge |
| 41 bool currVal = (*imagePtr != 0); | 42 unsigned char currVal = *imagePtr; |
| 43 unsigned char currCheck = (currVal >> 7); |
| 42 for (int i = 0; i < kNum8ConnectedNeighbors; ++i) { | 44 for (int i = 0; i < kNum8ConnectedNeighbors; ++i) { |
| 43 bool checkVal; | 45 unsigned char neighborVal; |
| 44 if ((1 << i) & neighborFlags) { | 46 if ((1 << i) & neighborFlags) { |
| 45 const unsigned char* checkPtr = imagePtr + offsets[i]; | 47 const unsigned char* checkPtr = imagePtr + offsets[i]; |
| 46 checkVal = (*checkPtr != 0); | 48 neighborVal = *checkPtr; |
| 47 } else { | 49 } else { |
| 48 checkVal = false; | 50 neighborVal = 0; |
| 49 } | 51 } |
| 50 SkASSERT(checkVal == 0 || checkVal == 1); | 52 unsigned char neighborCheck = (neighborVal >> 7); |
| 51 SkASSERT(currVal == 0 || currVal == 1); | 53 SkASSERT(currCheck == 0 || currCheck == 1); |
| 52 if (checkVal != currVal) { | 54 SkASSERT(neighborCheck == 0 || neighborCheck == 1); |
| 55 // if sharp transition |
| 56 if (currCheck != neighborCheck || |
| 57 // or both <128 and >0 |
| 58 (!currCheck && !neighborCheck && currVal && neighborVal)) { |
| 53 return true; | 59 return true; |
| 54 } | 60 } |
| 55 } | 61 } |
| 56 | 62 |
| 57 return false; | 63 return false; |
| 58 } | 64 } |
| 59 | 65 |
| 60 static void init_glyph_data(DFData* data, unsigned char* edges, const unsigned c
har* image, | 66 static void init_glyph_data(DFData* data, unsigned char* edges, const unsigned c
har* image, |
| 61 int dataWidth, int dataHeight, | 67 int dataWidth, int dataHeight, |
| 62 int imageWidth, int imageHeight, | 68 int imageWidth, int imageHeight, |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 // create temp data | 348 // create temp data |
| 343 size_t dataSize = dataWidth*dataHeight*sizeof(DFData); | 349 size_t dataSize = dataWidth*dataHeight*sizeof(DFData); |
| 344 SkAutoSMalloc<1024> dfStorage(dataSize); | 350 SkAutoSMalloc<1024> dfStorage(dataSize); |
| 345 DFData* dataPtr = (DFData*) dfStorage.get(); | 351 DFData* dataPtr = (DFData*) dfStorage.get(); |
| 346 sk_bzero(dataPtr, dataSize); | 352 sk_bzero(dataPtr, dataSize); |
| 347 | 353 |
| 348 SkAutoSMalloc<1024> edgeStorage(dataWidth*dataHeight*sizeof(char)); | 354 SkAutoSMalloc<1024> edgeStorage(dataWidth*dataHeight*sizeof(char)); |
| 349 unsigned char* edgePtr = (unsigned char*) edgeStorage.get(); | 355 unsigned char* edgePtr = (unsigned char*) edgeStorage.get(); |
| 350 sk_bzero(edgePtr, dataWidth*dataHeight*sizeof(char)); | 356 sk_bzero(edgePtr, dataWidth*dataHeight*sizeof(char)); |
| 351 | 357 |
| 358 SkAutoSMalloc<1024> copyStorage((width+2)*(height+2)*sizeof(char)); |
| 359 unsigned char* copyPtr = (unsigned char*) copyStorage.get(); |
| 360 |
| 361 // we copy our source image into a padded copy to ensure we catch edge trans
itions |
| 362 // around the outside |
| 363 const unsigned char* currImage = image; |
| 364 sk_bzero(copyPtr, (width+2)*sizeof(char)); |
| 365 unsigned char* currCopy = copyPtr + width + 2; |
| 366 for (int i = 0; i < height; ++i) { |
| 367 *currCopy++ = 0; |
| 368 memcpy(currCopy, currImage, width*sizeof(char)); |
| 369 currImage += width; |
| 370 currCopy += width; |
| 371 *currCopy++ = 0; |
| 372 } |
| 373 sk_bzero(currCopy, (width+2)*sizeof(char)); |
| 374 |
| 352 // copy glyph into distance field storage | 375 // copy glyph into distance field storage |
| 353 init_glyph_data(dataPtr, edgePtr, image, | 376 init_glyph_data(dataPtr, edgePtr, copyPtr, |
| 354 dataWidth, dataHeight, | 377 dataWidth, dataHeight, |
| 355 width, height, pad); | 378 width+2, height+2, pad-1); |
| 356 | 379 |
| 357 // create initial distance data, particularly at edges | 380 // create initial distance data, particularly at edges |
| 358 init_distances(dataPtr, edgePtr, dataWidth, dataHeight); | 381 init_distances(dataPtr, edgePtr, dataWidth, dataHeight); |
| 359 | 382 |
| 360 // now perform Euclidean distance transform to propagate distances | 383 // now perform Euclidean distance transform to propagate distances |
| 361 | 384 |
| 362 // forwards in y | 385 // forwards in y |
| 363 DFData* currData = dataPtr+dataWidth+1; // skip outer buffer | 386 DFData* currData = dataPtr+dataWidth+1; // skip outer buffer |
| 364 unsigned char* currEdge = edgePtr+dataWidth+1; | 387 unsigned char* currEdge = edgePtr+dataWidth+1; |
| 365 for (int j = 1; j < dataHeight-1; ++j) { | 388 for (int j = 1; j < dataHeight-1; ++j) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 currEdge -= dataWidth-1; | 442 currEdge -= dataWidth-1; |
| 420 } | 443 } |
| 421 | 444 |
| 422 // copy results to final distance field data | 445 // copy results to final distance field data |
| 423 currData = dataPtr + dataWidth+1; | 446 currData = dataPtr + dataWidth+1; |
| 424 currEdge = edgePtr + dataWidth+1; | 447 currEdge = edgePtr + dataWidth+1; |
| 425 unsigned char *dfPtr = distanceField; | 448 unsigned char *dfPtr = distanceField; |
| 426 for (int j = 1; j < dataHeight-1; ++j) { | 449 for (int j = 1; j < dataHeight-1; ++j) { |
| 427 for (int i = 1; i < dataWidth-1; ++i) { | 450 for (int i = 1; i < dataWidth-1; ++i) { |
| 428 #if DUMP_EDGE | 451 #if DUMP_EDGE |
| 429 unsigned char val = sk_float_round2int(255*currData->fAlpha); | 452 float alpha = currData->fAlpha; |
| 453 float edge = 0.0f; |
| 430 if (*currEdge) { | 454 if (*currEdge) { |
| 431 val = 128; | 455 edge = 0.25f; |
| 432 } | 456 } |
| 457 // blend with original image |
| 458 float result = alpha + (1.0f-alpha)*edge; |
| 459 unsigned char val = sk_float_round2int(255*result); |
| 433 *dfPtr++ = val; | 460 *dfPtr++ = val; |
| 434 #else | 461 #else |
| 435 float dist; | 462 float dist; |
| 436 if (currData->fAlpha > 0.5f) { | 463 if (currData->fAlpha > 0.5f) { |
| 437 dist = -SkScalarSqrt(currData->fDistSq); | 464 dist = -SkScalarSqrt(currData->fDistSq); |
| 438 } else { | 465 } else { |
| 439 dist = SkScalarSqrt(currData->fDistSq); | 466 dist = SkScalarSqrt(currData->fDistSq); |
| 440 } | 467 } |
| 441 *dfPtr++ = pack_distance_field_val(dist, (float)distanceMagnitude); | 468 *dfPtr++ = pack_distance_field_val(dist, (float)distanceMagnitude); |
| 442 #endif | 469 #endif |
| 443 ++currData; | 470 ++currData; |
| 444 ++currEdge; | 471 ++currEdge; |
| 445 } | 472 } |
| 446 currData += 2; | 473 currData += 2; |
| 447 currEdge += 2; | 474 currEdge += 2; |
| 448 } | 475 } |
| 449 | 476 |
| 450 return true; | 477 return true; |
| 451 } | 478 } |
| OLD | NEW |