ex) Canvas_drawRect
setStyle 종류 ( 도형을 어떻게 그릴것인지 결정 )
style 종류 | 의미 | 설명 | 시각적 예 |
kFill_Style | 채우기 전용 | 도형 안쪽을 채움 | ■ ● |
kStroke_Style | 선(테두리)만 그림 | 내부는 비우고 외곽선만 그림 | □ ○ |
kStrokeAndFill_Style | 채우고 선도 그림 | 안도 채우고 테두리도 그림 | ◎ ◉ |
setStrokeJoin 종류 ( 코너를 어떻게 그릴것인지 결정 )
stroke join 종류 | 의미 | 설명 | 시각적 예 |
SkPaint::kMiter_Join | 날카로운 모서리 (뾰족하게) 연결 | 기본값, 각도가 작을수록 길게 튀어나올 수 있음 | ┏━, ⎾ ┓ |
SkPaint::kBevel_Join | 모서리를 뚝 자른 형태로 연결 | 뾰족함 없이 평평하게 잘림 | ◣, ↘ |
SkPaint::kRound_Join | 모서리를 둥글게 연결 | 부드러운 느낌, 곡선 UI에 적합 | ⤾, ⤿, ◎ |
void draw(SkCanvas* canvas) {
SkPoint rectPts[] = { {64, 48}, {192, 160} };
SkPaint paint;
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(20);
paint.setStrokeJoin(SkPaint::kRound_Join);
SkMatrix rotator;
rotator.setRotate(30, 128, 128);
for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) {
paint.setColor(color);
SkRect rect;
rect.set(rectPts[0], rectPts[1]);
canvas->drawRect(rect, paint);
rotator.mapPoints(rectPts, 2);
}
}
Canvas_drawRegion
void draw(SkCanvas* canvas) {
SkRegion region;
region.op({10, 10, 50, 50}, SkRegion::kUnion_Op);
region.op({10, 50, 90, 90}, SkRegion::kUnion_Op);
SkPaint paint;
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(20);
paint.setStrokeJoin(SkPaint::kRound_Join);
canvas->drawRegion(region, paint);
}
SkRegion::OP | 설명 | 예시 |
kUnion_Op | 기존 Region과 새 영역의 합집합 | 둘 중 하나라도 포함되면 포함 |
kIntersect_Op | 겹치는 부분만 남김 | 둘 다 포함되는 영역만 유지 |
kDifference_Op | 기존 Region에서 새 영역을 제거 | 기존 영역에서 겹친 부분 빼기 |
kXOR_Op | 겹치지 않는 부분만 남김 | A 또는 B에만 속한 영역 |
kReverseDifference_Op | 새 영역에서 기존 Region을 제거 | 새 영역에서 겹친 부분 빼기 |
kReplace_Op | 기존 Region을 새 영역으로 완전히 대체 | 이전 Region은 무시됨 |
region.op({...}, kUnion_OP)
- kUnion_OP로 설정이 되어 있어서 두 영역의 합집합 부분이 region으로 처리됨. ㄴ 자로 렌더링
- kIntersect_Op로 설정 하면, 겹치는 부분이 없기 때문에 아무것도 나오지 않는다.
paint.setStyle(SkPaint::KStroke_Style)
- 내부를 채우지 않고 테두리만 렌더링
setStrokeJoin(SkPint::KRound_Join)
- 테두리 코너 영역 라운드 처리
Canvas_drawLine
void draw(SkCanvas* canvas) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(0xFF9a67be);
paint.setStrokeWidth(20);
canvas->skew(1, 0);
canvas->drawLine(32, 96, 32, 160, paint);
canvas->skew(-2, 0);
canvas->drawLine(288, 96, 288, 160, paint);
}
Canvas_drawPicture_4
void draw(SkCanvas* canvas) {
SkPaint paint;
SkPictureRecorder recorder;
// 1. SkPictureRecorder로 50x50 영역의 캔버스에 그림을 "기록" 시작
SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
// 2. 세 가지 색상으로 반복해서 사각형을 그리되, 매번 변형을 누적 적용함
for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 }) {
paint.setColor(color); // 현재 색상 설정
recordingCanvas->drawRect({10, 10, 30, 40}, paint); // (10,10)-(30,40)에 사각형 그림
recordingCanvas->translate(10, 10); // 이후 명령에 대해 캔버스를 (10,10)만큼 이동시킴
recordingCanvas->scale(1.0f, 2.0f); // 이후 명령에 대해 Y축 방향으로 2배 스케일 적용
// → transform은 누적되므로 두 번째, 세 번째 사각형은 위치와 크기가 달라짐
}
// 3. 기록을 종료하고 SkPicture 객체를 생성
sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
// 4. SkPicture를 캔버스에 3번 재생하되, 각기 다른 alpha 값과 위치에서 그림
SkMatrix matrix;
matrix.reset(); // 초기 행렬은 항등 행렬 (변형 없음)
for (auto alpha : { 70, 140, 210 }) {
paint.setAlpha(alpha); // 투명도 설정 (점점 더 불투명해짐)
canvas->drawPicture(playback, &matrix, &paint); // SkPicture 재생
matrix.preTranslate(70, 70); // 다음 반복에서 그림 위치를 (70,70)만큼 이동
}
}
beginRecording(w, h)를 호출하면 그림을 기록할 수 있는 SkCanvas * 를 리턴 받고,
해당 캔버스로 그림을 기록!
finishRecordingAsPicture()를 통해 기록된 내용을 재생가능한 객체 SkPicture로 전달 받음.
translate -> scale 순서대로 호출하면, 역순으로 적용이 된다.
BLUE 경우 Y 좌표 2배를 곱하고, translate (10, 10)
GREEN 경우 Y 좌표 4배( 2배 * 2배) , translate (10 * 2 , 10 * 2)
색상 | 사각형의 크기 | 설명 |
RED | (10, 10) ~ (30, 40) | 기본 상태 |
BLUE | (20, 30) ~ (40, 90) | (10, 10) ~ (30, 40) * 2 (y) (10, 20) ~ (30, 80) + (10, 10) (20, 30) ~ (40, 90) |
GREEN | (30, 60) ~ (50, 180) | (10, 10) ~ (30, 40) * 4(y) (10, 40) ~ (30, 160) + (20, 20) (30, 60) ~ (50, 180) |
세번째 초록색 사각형은 Picture의 50, 50에 잘려서 보이지 않는다.
Canvas_drawString
void draw(SkCanvas* canvas) {
SkPaint paint;
// 2. 기본 글꼴을 검색해서 SkFont 생성
SkFont font = SkFont(fontMgr->matchFamilyStyle(nullptr, {}));
// 3. 텍스트 출력
canvas->drawString("a small hello", 20, 20, font, paint);
}
matchFamilyStyle 함수
- nullptr: 기본 글꼴 패밀리 사용 (예: sans-serif)
- {}: 기본 스타일 (보통 Regular)
파라메터 | 타입 | 설명 |
familyName | const char* | 글꼴 패밀리 이름 (예: "Arial", "Noto Sans") nullptr이면 시스템 기본 글꼴 사용 |
style | const SkFontStyle& | 글꼴의 굵기(weight), 기울임(slant), 너비(width) 설정 예: SkFontStyle::Bold(), {700, 5, SkFontStyle::kItalic_Slant} 등 |
drawString
파라메터 | 타입 | 설명 |
text | const char* | 출력할 문자열 (UTF-8) |
x, y | SkScalar | 출력 위치 (텍스트의 baseline 기준 좌표) 바닥선 |
font | const SkFont& | 사용할 글꼴 정보 (SkTypeface, size 포함) |
paint | const SkPaint& | 색상, 안티앨리어싱 등 스타일 지정 |
Canvas_drawText
void draw(SkCanvas* canvas) {
SkPaint paint;
SkFont defaultFont = SkFont(fontMgr->matchFamilyStyle(nullptr, {}));
float textSizes[] = { 12, 18, 24, 36 };
for (auto size: textSizes ) {
defaultFont.setSize(size);
canvas->drawString("Aa", 10, 20, defaultFont, paint);
canvas->translate(0, size * 2);
}
defaultFont = SkFont(fontMgr->matchFamilyStyle(nullptr, {}));
float yPos = 20;
for (auto size: textSizes ) {
float scale = size / 12.f;
canvas->resetMatrix();
canvas->translate(100, 0);
canvas->scale(scale, scale);
canvas->drawString("Aa", 10 / scale, yPos / scale, defaultFont, paint);
yPos += size * 2;
}
}
텍스트 | 크기 | x | y |
Aa | 12 | 10 | 20 |
Aa | 24 | 10 | 20 + 12×2 = 44 |
Aa | 36 | 10 | 44 + 24×2 = 92 |
텍스트 | 크기 | 스케일 | x(10 / s) | y(yPos / s) |
Aa | 12 | 1.0 | 10 | 20 |
Aa | 24 | 2.0 | 5 | 22 |
Aa | 36 | 3.0 | 3.33 | 30.67 |
Canvas_drawVertices
내일
void draw(SkCanvas* canvas) {
SkPaint paint;
SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
std::size(points), points, nullptr, colors);
canvas->drawVertices(vertices.get(), SkBlendMode::kDst, paint);
}
'Algorithm' 카테고리의 다른 글
BackTracking 3 (1) | 2024.06.15 |
---|---|
BackTracking 2 (1) | 2024.06.15 |
BackTracking 1 (0) | 2024.06.15 |
Dynamic Programing 4 (0) | 2024.06.15 |
Dynamic Programing 3 (0) | 2024.06.15 |