// This code draws a bitmap using the full m_CTM transform without any thought // to whether or not the transform has any special properties. void drawBitmapXForm(const GBitmap &bm, const GPaint &paint) { const GBitmap &ctxbm = GetInternalBitmap(); GRect ctxRect = GRect::MakeXYWH(0, 0, ctxbm.width(), ctxbm.height()); GIRect bmRect = GIRect::MakeXYWH(0, 0, bm.width(), bm.height()); GRect pixelRect = GetTransformedBoundingBox(bmRect); GRect rect; if(!(rect.setIntersection(ctxRect, pixelRect))) { return; } // Rein everything back into integer land GIRect dstRect = rect.round(); if(dstRect.isEmpty()) { return; } float alpha = paint.getAlpha(); if(alpha >= kOpaqueAlpha) { for(uint32_t j = 0; j < dstRect.height(); j++) { for(uint32_t i = 0; i < dstRect.width(); i++) { drawXFormPixel(i, j, dstRect, bmRect, bm, ctxbm); } } } else { const uint32_t alphaVal = static_cast<uint32_t>((alpha * 255.0f) + 0.5f); for(uint32_t j = 0; j < dstRect.height(); j++) { for(uint32_t i = 0; i < dstRect.width(); i++) { drawXFormPixelWithAlpha(i, j, dstRect, bmRect, bm, ctxbm, alphaVal); } } } }
MyCanvas::MyCanvas(const GBitmap& bitmap): Bitmap(bitmap), BmpRect(GIRect::MakeWH(bitmap.width(), bitmap.height())), CTM() { /* Push the identity matrix onto the matrix stack */ MatrixStack.push(CTM); }
static void draw_bitmaps(GCanvas* canvas) { GBitmap tex; tex.readFromFile("spock_png"); canvas->fillRectBitmap(GRect::MakeWH(tex.width(), tex.height()), tex); canvas->fillRectBitmap(GRect::MakeLTRB(10, 140, 138, 500), tex); canvas->fillRectBitmap(GRect::MakeLTRB(140, 10, 500, 138), tex); canvas->fillRectBitmap(GRect::MakeXYWH(256, 256, 512, 512), tex); }
void scaleAboutCenter(GContext* ctx) { GBitmap bm; ctx->getBitmap(&bm); float cx = bm.width() * 0.5f; float cy = bm.height() * 0.5f; ctx->translate(cx, cy); ctx->scale(fScale, fScale); ctx->translate(-cx, -cy); }
static void draw_ramp(const GBitmap& bitmap) { const float g0 = 0; const float g1 = 255; const float dg = (g1 - g0) / bitmap.width(); const float b0 = 0; const float b1 = 255; const float db = (b1 - b0) / bitmap.height(); GPixel* dst = bitmap.fPixels; float g = g0 + dg/2; for (int y = 0; y < bitmap.height(); ++y) { float b = b0 + db/2; for (int x = 0; x < bitmap.width(); ++x) { dst[x] = GPixel_PackARGB(0xFF, 0, (int)g, (int)b); b += db; } g += dg; dst = (GPixel*)((char*)dst + bitmap.rowBytes()); } }
static void draw_circle(const GBitmap& bitmap) { const GPixel px = GPixel_PackARGB(0xFF, 0xFF, 0, 0); const float cx = (float)bitmap.width() / 2; const float cy = (float)bitmap.height() / 2; const float radius = cx * 5 / 6; const float radius2 = radius * radius; GPixel* dst = bitmap.pixels(); for (int y = 0; y < bitmap.height(); ++y) { const float dy = y - cy; for (int x = 0; x < bitmap.width(); ++x) { const float dx = x - cx; const float dist2 = dx*dx + dy*dy; if (dist2 <= radius2) { dst[x] = px; } else { dst[x] = 0; // transparent } } dst = (GPixel*)((char*)dst + bitmap.rowBytes()); } }
PolyShape(const GBitmap& bm, int x, int y) : Shape(x, y) { fCount = gRand.nextRange(3, 20); fPts = new GPoint[fCount]; float scaleX = bm.width() * .5f; float scaleY = bm.height() * .5f; for (int i = 0; i < fCount; ++i) { float angle = i * 2 * 3.14159265359 / fCount; float sv, cv; cv = cos_sin(angle, &sv); fPts[i].set(scaleX * sv, scaleY * cv); } fPaint.setRGB(gRand.nextF(), gRand.nextF(), gRand.nextF()); }
static void make_circle(const GBitmap& bitmap, const GColor& color) { const GPixel px = pin_and_premul_to_pixel(color); const float cx = (float)bitmap.width() / 2; const float cy = (float)bitmap.height() / 2; const float radius = cx - 1; const float radius2 = radius * radius; GPixel* dst = bitmap.pixels(); for (int y = 0; y < bitmap.height(); ++y) { const float dy = y - cy; for (int x = 0; x < bitmap.width(); ++x) { const float dx = x - cx; const float dist2 = dx*dx + dy*dy; if (dist2 <= radius2) { dst[x] = px; } else { dst[x] = 0; // transparent } } dst = (GPixel*)((char*)dst + bitmap.rowBytes()); } }
/* * The bitmap has already been sized and allocated. This function's job is to fill in the * pixels to create the custom image. See src/image.cpp for examples. */ void cs575_draw_into_bitmap(const GBitmap& bitmap) { // // Your code goes here // const float rx = 200; const float ry = 50; const float rz = (rx - ry)/bitmap.width(); const float bx = 50; const float by = 200; const float bz = (by - bx)/bitmap.width(); GPixel* dst = bitmap.fPixels; float r = rx + rz/4; for (int y = 0; y < bitmap.height(); ++y) { float b = bx + bz/4; for (int x = 0; x < bitmap.width(); ++x) { dst[x] = GPixel_PackARGB(0xFF, (int)r, 0, (int)b); b += bz; } r += rz; dst = (GPixel*)((char*)dst + bitmap.rowBytes()); } }
void MyCanvas::fillBitmapRect(const GBitmap& src, const GRect& dst) { if (dst.isEmpty()) { printf("Error: FillBitmapRect dst rect is empty\n"); return; } /* Get the matrix of the conversion from src to dst rect * Use the rect to rect matrix to create bitmap shader */ auto LocalMatrix = Utility::RectToRect(GRect::MakeWH(src.width(), src.height()), dst); float localArr[6]; LocalMatrix.GetTwoRows(localArr); GShader* shader = GShader::FromBitmap(src, localArr); shadeRect(dst, shader); delete shader; }
static void fill_circle(const GBitmap& bm) { int w = bm.width(); int h = bm.height(); int r = (w < h ? w : h) >> 1; float cx = w/2; float cy = h/2; float rr = (float)r * r; GPixel* row = bm.fPixels; for (int y = 0; y < h; ++y) { float dy2 = (y - cy) * (y - cy); for (int x = 0; x < w; ++x) { float dx2 = (x - cx) * (x - cx); if (dx2 + dy2 > rr) { row[x] = 0; } } row = next_row(bm, row); } }
RectShape(const GBitmap& bm, int x, int y) : Shape(x, y) { fRect.setXYWH(x, y, bm.width(), bm.height()); fRect.offset(-fRect.centerX(), -fRect.centerY()); fPaint.setRGB(gRand.nextF(), gRand.nextF(), gRand.nextF()); }
/** * Scale and translate the bitmap such that is fills the specific rectangle. * * Any area in the rectangle that is outside of the bounds of the canvas is ignored. * * If a given pixel in the bitmap is not opaque (e.g. GPixel_GetA() < 255) then blend it * using SRCOVER blend mode. */ void fillBitmapRect(const GBitmap& src, const GRect& dst) { // Store dimensions of dst rectangle int left = dst.left(); int top = dst.top(); int right = dst.right(); int bottom = dst.bottom(); int rW = dst.width(); int rH = dst.height(); // Store dimensions of src bitmap int bW = src.width(); int bH = src.height(); // Find necessary scale factor for both width and height float sx = (float)bW/(float)rW; float sy = (float)bH/(float)rH; float tx = 0 - left; float ty = 0 - top; // Create matrix for scaling float scale[6] = {sx, 0, 0, 0, sy, 0}; // Create matrix for translating float translate[6] = {1, 0, tx, 0, 1, ty}; // Combine the matrices float both[6] = {sx, 0, sx*tx, 0, sy, sy*ty}; // For loop that takes each point in dst and find corresponding point in src GPixel* d = draw.fPixels; d = (GPixel*)((char*)d + (int)top * draw.rowBytes()); for (int y = top; y < bottom; ++y) { for (int x = left; x < right; ++x) { // Only map pixels that are in the bitmap if ((x >= 0 && x < draw.width()) && (y >= 0 && y < draw.height())) { // Find corresponding point in src bitmap int xP; int yP; xP = both[0] * x + both[1] * y + both[2]; yP = both[3] * x + both[4] * y + both[5]; // Apply CTM to x and y int nX = (CTM[0] * x) + (CTM[1] * y) + (CTM[2]); int nY = (CTM[3] * x) + (CTM[4] * y) + (CTM[5]); // Prepare color to fill unsigned a = GPixel_GetA(*src.getAddr(xP, yP)); unsigned r = GPixel_GetR(*src.getAddr(xP, yP)); unsigned g = GPixel_GetG(*src.getAddr(xP, yP)); unsigned b = GPixel_GetB(*src.getAddr(xP, yP)); unsigned nA = a; unsigned nR = r; unsigned nG = g; unsigned nB = b; if (GPixel_GetA(*draw.getAddr(x, y)) > 0) { // blend float lA = GPixel_GetA(*src.getAddr(xP, yP)) / 255.99999; float lR = GPixel_GetR(*src.getAddr(xP, yP)) / 255.99999; float lG = GPixel_GetG(*src.getAddr(xP, yP)) / 255.99999; float lB = GPixel_GetB(*src.getAddr(xP, yP)) / 255.99999; float sA = lA + ((GPixel_GetA(*draw.getAddr(x, y)) / 255.99999) * (1.0f - lA)); float sR = lR + ((GPixel_GetR(*draw.getAddr(x, y)) / 255.99999) * (1.0f - lA)); float sG = lG + ((GPixel_GetG(*draw.getAddr(x, y)) / 255.99999) * (1.0f - lA)); float sB = lB + ((GPixel_GetB(*draw.getAddr(x, y)) / 255.99999) * (1.0f - lA)); /* float sA = lA + ((GPixel_GetA(*draw.getAddr(nX, nY)) / 255.99999) * (1.0f - lA)); float sR = lR + ((GPixel_GetR(*draw.getAddr(nX, nY)) / 255.99999) * (1.0f - lA)); float sG = lG + ((GPixel_GetG(*draw.getAddr(nX, nY)) / 255.99999) * (1.0f - lA)); float sB = lB + ((GPixel_GetB(*draw.getAddr(nX, nY)) / 255.99999) * (1.0f - lA)); */ nA = (int)(sA * 255.99999); nR = (int)(sR * 255.99999); nG = (int)(sG * 255.99999); nB = (int)(sB * 255.99999); d[x] = GPixel_PackARGB(nA, nR, nG, nB); //d = (GPixel*)((char*)d + (int)nY * draw.rowBytes()); //d[nX] = GPixel_PackARGB(nA, nR, nG, nB); //d = (GPixel*)((char*)d - (int)nY * draw.rowBytes()); } else { d[x] = GPixel_PackARGB(a, r, g, b); //d = (GPixel*)((char*)d + (int)nY * draw.rowBytes()); //d[nX] = GPixel_PackARGB(a, r, g, b); //d = (GPixel*)((char*)d - (int)nY * draw.rowBytes()); } } } d = (GPixel*)((char*)d + draw.rowBytes()); } }
BitmapShape(const GBitmap& bm) : fBM(bm) { const int w = std::max(bm.width(), 100); const int h = std::max(bm.height(), 100); fRect = GRect::MakeXYWH(100, 100, w, h); }
// This code draws a bitmap assuming that we only have translation and scale, // which allows us to perform certain optimizations... void drawBitmapSimple(const GBitmap &bm, const GPaint &paint) { const GBitmap &ctxbm = GetInternalBitmap(); GRect ctxRect = GRect::MakeXYWH(0, 0, ctxbm.width(), ctxbm.height()); GRect bmRect = GRect::MakeXYWH(0, 0, bm.width(), bm.height()); GRect pixelRect = GetTransformedBoundingBox(bmRect); GRect rect; if(!(rect.setIntersection(ctxRect, pixelRect))) { return; } // We know that since we're only doing scale and translation, that all of the pixel // centers contained in rect are going to be drawn, so we only need to know the // dimensions of the mapping... GVec3f origin(0, 0, 1); GVec3f offset(1, 1, 1); origin = m_CTM * origin; offset = m_CTM * offset; float xScale = 1.0f / (offset.X() - origin.X()); float yScale = 1.0f / (offset.Y() - origin.Y()); GVec2f start = GVec2f(0, 0); if(xScale < 0.0f) { start.X() = pixelRect.fRight - 1.0f; } if(yScale < 0.0f) { start.Y() = pixelRect.fBottom - 1.0f; } GIRect dstRect = rect.round(); // Construct new bitmap int32_t offsetX = ::std::max(0, -dstRect.fLeft); int32_t offsetY = ::std::max(0, -dstRect.fTop); GBitmap fbm; fbm.fWidth = bm.width(); fbm.fHeight = bm.height(); fbm.fPixels = GetRow(bm, offsetY) + offsetX; fbm.fRowBytes = bm.fRowBytes; BlendFunc blend = blend_srcover; float alpha = paint.getAlpha(); if(alpha >= kOpaqueAlpha) { for(uint32_t j = 0; j < dstRect.height(); j++) { uint32_t srcIdxY = static_cast<uint32_t>(start.Y() + static_cast<float>(j) * yScale); GPixel *srcPixels = GetRow(fbm, Clamp<int>(srcIdxY, 0, fbm.height())); GPixel *dstPixels = GetRow(ctxbm, dstRect.fTop + j) + dstRect.fLeft; for(uint32_t i = 0; i < dstRect.width(); i++) { uint32_t srcIdxX = static_cast<uint32_t>(start.X() + static_cast<float>(i) * xScale); dstPixels[i] = blend(dstPixels[i], srcPixels[Clamp<int>(srcIdxX, 0, fbm.width())]); } } } else { const uint32_t alphaVal = static_cast<uint32_t>((alpha * 255.0f) + 0.5f); for(uint32_t j = 0; j < dstRect.height(); j++) { uint32_t srcIdxY = static_cast<uint32_t>(start.Y() + static_cast<float>(j) * yScale); GPixel *srcPixels = GetRow(fbm, srcIdxY); GPixel *dstPixels = GetRow(ctxbm, dstRect.fTop + j) + dstRect.fLeft; for(uint32_t i = 0; i < dstRect.width(); i++) { uint32_t srcIdxX = static_cast<uint32_t>(start.X() + static_cast<float>(i) * xScale); uint32_t srcA = fixed_multiply(GPixel_GetA(srcPixels[srcIdxX]), alphaVal); uint32_t srcR = fixed_multiply(GPixel_GetR(srcPixels[srcIdxX]), alphaVal); uint32_t srcG = fixed_multiply(GPixel_GetG(srcPixels[srcIdxX]), alphaVal); uint32_t srcB = fixed_multiply(GPixel_GetB(srcPixels[srcIdxX]), alphaVal); GPixel src = GPixel_PackARGB(srcA, srcR, srcG, srcB); dstPixels[i] = blend(dstPixels[i], src); } } } }