InterpolationQuality GraphicsContext::imageInterpolationQuality() const { if (paintingDisabled()) return InterpolationDefault; CGInterpolationQuality quality = CGContextGetInterpolationQuality(platformContext()); switch (quality) { case kCGInterpolationDefault: return InterpolationDefault; case kCGInterpolationNone: return InterpolationNone; case kCGInterpolationLow: return InterpolationLow; #if HAVE(CG_INTERPOLATION_MEDIUM) // kCGInterpolationMedium is known to be present in the CGInterpolationQuality enum. case kCGInterpolationMedium: #if USE(CG_INTERPOLATION_MEDIUM) // Only map to InterpolationMedium if targeting a system that understands it. return InterpolationMedium; #else return InterpolationDefault; #endif // USE(CG_INTERPOLATION_MEDIUM) #endif // HAVE(CG_INTERPOLATION_MEDIUM) case kCGInterpolationHigh: return InterpolationHigh; } return InterpolationDefault; }
bool GiCanvasIos::drawCachedBitmap2(const GiCanvas* p, float x, float y, bool secondBmp) { bool ret = false; if (p && p->getCanvasType() == getCanvasType()) { GiCanvasIos* gs = (GiCanvasIos*)p; int index = secondBmp ? 1 : 0; CGImageRef image = gs->m_draw->_cacheserr[index] ? NULL : gs->m_draw->_caches[index]; CGContextRef context = m_draw->getContext(); if (context && image) { CGRect rect = CGRectMake(x, y, m_draw->width(), m_draw->height()); CGAffineTransform af = CGAffineTransformMake(1, 0, 0, -1, 0, m_draw->height()); CGContextConcatCTM(context, af); CGInterpolationQuality oldQuality = CGContextGetInterpolationQuality(context); CGContextSetInterpolationQuality(context, kCGInterpolationNone); CGContextDrawImage(context, rect, image); CGContextSetInterpolationQuality(context, oldQuality); CGContextConcatCTM(context, CGAffineTransformInvert(af)); ret = true; } } return ret; }
void GiCanvasIos::endPaint(bool draw) { if (m_draw->getContext()) { if (draw && m_draw->_buffctx && m_draw->_context) { CGContextRef context = m_draw->_context; CGImageRef image = CGBitmapContextCreateImage(m_draw->_buffctx); CGRect rect = CGRectMake(0, 0, m_draw->width(), m_draw->height()); // 逻辑宽高点数 if (image) { CGAffineTransform af = CGAffineTransformMake(1, 0, 0, -1, 0, m_draw->height()); CGContextConcatCTM(context, af); // 图像是朝上的,上下文坐标系朝下,上下颠倒显示 CGInterpolationQuality old = CGContextGetInterpolationQuality(context); CGContextSetInterpolationQuality(context, kCGInterpolationNone); CGContextDrawImage(context, rect, image); CGContextSetInterpolationQuality(context, old); CGContextConcatCTM(context, CGAffineTransformInvert(af)); // 恢复成坐标系朝下 CGImageRelease(image); } } if (m_draw->_buffctx) { CGContextRelease(m_draw->_buffctx); m_draw->_buffctx = NULL; } m_draw->_context = NULL; if (owner()) owner()->_endPaint(); } }
bool GiCanvasIos::drawCachedBitmap(float x, float y, bool secondBmp) { int index = secondBmp ? 1 : 0; CGImageRef image = m_draw->_cacheserr[index] ? NULL : m_draw->_caches[index]; CGContextRef context = m_draw->getContext(); bool ret = false; if (context && image) { CGRect rect = CGRectMake(x, y, m_draw->width(), m_draw->height()); CGAffineTransform af = CGAffineTransformMake(1, 0, 0, -1, 0, m_draw->height()); CGContextConcatCTM(context, af); // 图像是朝上的,上下文坐标系朝下,上下颠倒显示 CGInterpolationQuality oldQuality = CGContextGetInterpolationQuality(context); CGContextSetInterpolationQuality(context, kCGInterpolationNone); CGContextDrawImage(context, rect, image); CGContextSetInterpolationQuality(context, oldQuality); CGContextConcatCTM(context, CGAffineTransformInvert(af)); // 恢复成坐标系朝下 ret = true; } return ret; }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); RetainPtr<CGImageRef> image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } float currHeight = CGImageGetHeight(image.get()); if (currHeight <= srcRect.y()) return; CGContextRef context = ctxt->platformContext(); ctxt->save(); bool shouldUseSubimage = false; // If the source rect is a subportion of the image, then we compute an inflated destination rect that will hold the entire image // and then set a clip to the portion that we want to display. FloatRect adjustedDestRect = destRect; FloatSize selfSize = currentFrameSize(); if (srcRect.size() != selfSize) { CGInterpolationQuality interpolationQuality = CGContextGetInterpolationQuality(context); // When the image is scaled using high-quality interpolation, we create a temporary CGImage // containing only the portion we want to display. We need to do this because high-quality // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed // into the destination rect. See <rdar://problem/6112909>. shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped()); float xScale = srcRect.width() / destRect.width(); float yScale = srcRect.height() / destRect.height(); if (shouldUseSubimage) { FloatRect subimageRect = srcRect; float leftPadding = srcRect.x() - floorf(srcRect.x()); float topPadding = srcRect.y() - floorf(srcRect.y()); subimageRect.move(-leftPadding, -topPadding); adjustedDestRect.move(-leftPadding / xScale, -topPadding / yScale); subimageRect.setWidth(ceilf(subimageRect.width() + leftPadding)); adjustedDestRect.setWidth(subimageRect.width() / xScale); subimageRect.setHeight(ceilf(subimageRect.height() + topPadding)); adjustedDestRect.setHeight(subimageRect.height() / yScale); image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect)); if (currHeight < srcRect.bottom()) { ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y); adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale); } } else { adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale)); adjustedDestRect.setSize(FloatSize(selfSize.width() / xScale, selfSize.height() / yScale)); } CGContextClipToRect(context, destRect); } // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. if (!shouldUseSubimage && currHeight < selfSize.height()) adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height()); ctxt->setCompositeOperation(compositeOp); // Flip the coords. CGContextScaleCTM(context, 1, -1); adjustedDestRect.setY(-adjustedDestRect.bottom()); // Adjust the color space. image = imageWithColorSpace(image.get(), styleColorSpace); // Draw the image. CGContextDrawImage(context, adjustedDestRect, image.get()); ctxt->restore(); if (imageObserver()) imageObserver()->didDraw(this); }