static void vg_copy_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch) { vg_t *vg = (vg_t*)data; if (vg->mEglImageBuf) { EGLImageKHR img = 0; bool new_egl = vg->driver->write_egl_image(frame, width, height, pitch, (vg->mTexType == VG_sXRGB_8888), 0, &img); rarch_assert(img != EGL_NO_IMAGE_KHR); if (new_egl) { vgDestroyImage(vg->mImage); vg->mImage = pvgCreateEGLImageTargetKHR((VGeglImageKHR) img); if (!vg->mImage) { RARCH_ERR("[VG:EGLImage] Error creating image: %08x\n", vgGetError()); exit(2); } vg->last_egl_image = img; } } else { vgImageSubData(vg->mImage, frame, pitch, vg->mTexType, 0, 0, width, height); } }
static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { bool ret = false; if (index >= MAX_EGLIMAGE_TEXTURES) { *image_handle = NULL; return false; } eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(g_egl_dpy, g_pbuff_surf, g_pbuff_surf, g_eglimage_ctx); if (!eglBuffer[index] || !g_egl_vgimage[index]) { g_egl_vgimage[index] = vgCreateImage(rgb32 ? VG_sXRGB_8888 : VG_sRGB_565, g_egl_res, g_egl_res, VG_IMAGE_QUALITY_NONANTIALIASED); eglBuffer[index] = peglCreateImageKHR(g_egl_dpy, g_eglimage_ctx, EGL_VG_PARENT_IMAGE_KHR, (EGLClientBuffer)g_egl_vgimage[index], NULL); ret = true; } vgImageSubData(g_egl_vgimage[index], frame, pitch, (rgb32 ? VG_sXRGB_8888 : VG_sRGB_565), 0, 0, width, height); *image_handle = eglBuffer[index]; gfx_ctx_bind_api(g_api); eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx); return ret; }
static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { rpi_t *rpi = (rpi_t*)data; if (width != rpi->mRenderWidth || height != rpi->mRenderHeight) { rpi->mRenderWidth = width; rpi->mRenderHeight = height; rpi_calculate_quad(rpi); vguComputeWarpQuadToQuad( rpi->x1, rpi->y1, rpi->x2, rpi->y1, rpi->x2, rpi->y2, rpi->x1, rpi->y2, // needs to be flipped, Khronos loves their bottom-left origin 0, height, width, height, width, 0, 0, 0, rpi->mTransformMatrix); vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); vgLoadMatrix(rpi->mTransformMatrix); } vgSeti(VG_SCISSORING, VG_FALSE); vgClear(0, 0, rpi->mScreenWidth, rpi->mScreenHeight); vgSeti(VG_SCISSORING, VG_TRUE); vgImageSubData(rpi->mImage, frame, pitch, rpi->mTexType, 0, 0, width, height); vgDrawImage(rpi->mImage); #ifdef HAVE_FREETYPE if (msg && rpi->mFontsOn) rpi_draw_message(rpi, msg); #else (void)msg; #endif eglSwapBuffers(rpi->mDisplay, rpi->mSurface); return true; }
// makeimage makes an image from a raw raster of red, green, blue, alpha values void makeimage(VGfloat x, VGfloat y, int w, int h, VGubyte * data) { unsigned int dstride = w * 4; VGImageFormat rgbaFormat = VG_sABGR_8888; VGImage img = vgCreateImage(rgbaFormat, w, h, VG_IMAGE_QUALITY_BETTER); vgImageSubData(img, (void *)data, dstride, rgbaFormat, 0, 0, w, h); vgSetPixels(x, y, img, 0, 0, w, h); vgDestroyImage(img); }
int render(int width, int height) { static DWORD startTick =0; static DWORD frames = 0; VGImage image; char buf[256]; if((startTick == 0)||(frames > 50)) { if(frames > 50) frames = 0; startTick = GetTickCount(); frames++; } else { sprintf(buf, "fps:%2.2f frames/sec \n", (float)(frames++)*1000/(GetTickCount() - startTick)); OutputDebugString(buf); } if(pReadFile == NULL) { pReadFile = fopen("test.rgb","rb"); if(pReadFile) fseek(pReadFile, 0 , SEEK_SET); } if(pReadFile && (feof(pReadFile))) fseek(pReadFile, 0 , SEEK_SET); if(pReadFile) fread(pBuff, sizeof(BYTE),SRC_WIDTH*SRC_HEIGHT*2,pReadFile); image = vgCreateImage( VG_sRGB_565, SRC_WIDTH, SRC_HEIGHT, VG_IMAGE_QUALITY_BETTER ); if(image == NULL) return -1; vgImageSubData( image, pBuff, SRC_WIDTH*2, VG_sRGB_565, 0, 0, SRC_WIDTH, SRC_HEIGHT); vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); vgLoadIdentity(); vgScale((VGfloat)width/SRC_WIDTH, (VGfloat)height/SRC_HEIGHT); vgTranslate(SRC_WIDTH, SRC_HEIGHT); vgRotate(180.0f); vgDrawImage( image ); vgDestroyImage( image ); if ( vgGetError() == VG_NO_ERROR ) eglSwapBuffers( egldisplay, eglsurface ); return 0; }
NativeImagePtr RGBA32Buffer::asNewNativeImage() const { if (!m_image) { static const VGImageFormat bufferFormat = VG_sARGB_8888_PRE; // Save memory by using 16-bit images for fully opaque images. const VGImageFormat imageFormat = hasAlpha() ? WEBKIT_OPENVG_NATIVE_IMAGE_FORMAT_s_8888 : VG_sRGB_565; #if PLATFORM(EGL) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif const IntSize vgMaxImageSize(vgGeti(VG_MAX_IMAGE_WIDTH), vgGeti(VG_MAX_IMAGE_HEIGHT)); ASSERT_VG_NO_ERROR(); PassRefPtr<TiledImageOpenVG> tiledImage = adoptRef(new TiledImageOpenVG( IntSize(width(), height()), vgMaxImageSize)); const int numColumns = tiledImage->numColumns(); const int numRows = tiledImage->numRows(); for (int yIndex = 0; yIndex < numRows; ++yIndex) { for (int xIndex = 0; xIndex < numColumns; ++xIndex) { IntRect tileRect = tiledImage->tileRect(xIndex, yIndex); VGImage tile = vgCreateImage(imageFormat, tileRect.width(), tileRect.height(), VG_IMAGE_QUALITY_FASTER); ASSERT_VG_NO_ERROR(); PixelData* pixelData = m_bytes.data(); pixelData += (tileRect.y() * width()) + tileRect.x(); vgImageSubData(tile, reinterpret_cast<unsigned char*>(pixelData), width() * sizeof(PixelData), bufferFormat, 0, 0, tileRect.width(), tileRect.height()); ASSERT_VG_NO_ERROR(); tiledImage->setTile(xIndex, yIndex, tile); } } // Incomplete images will be returned without storing them in m_image, // so the image will be regenerated once loading is complete. if (m_status != FrameComplete) return tiledImage; m_image = tiledImage; m_bytes.clear(); } return m_image; // and increase refcount }
VGImage QVGPixmapData::toVGImage() { if (!isValid() || failedToAlloc) return VG_INVALID_HANDLE; #if !defined(QT_NO_EGL) // Increase the reference count on the shared context. if (!context) context = qt_vg_create_context(0, QInternal::Pixmap); #endif if (recreate && prevSize != QSize(w, h)) destroyImages(); else if (recreate) cachedOpacity = -1.0f; // Force opacity image to be refreshed later. #if defined(Q_OS_SYMBIAN) if (recreate && nativeImageHandleProvider && !nativeImageHandle) { createFromNativeImageHandleProvider(); } #endif if (vgImage == VG_INVALID_HANDLE) { vgImage = QVGImagePool::instance()->createImageForPixmap (qt_vg_image_to_vg_format(source.format()), w, h, VG_IMAGE_QUALITY_FASTER, this); // Bail out if we run out of GPU memory - try again next time. if (vgImage == VG_INVALID_HANDLE) { failedToAlloc = true; return VG_INVALID_HANDLE; } inImagePool = true; } else if (inImagePool) { QVGImagePool::instance()->useImage(this); } if (!source.isNull() && recreate) { source.beginDataAccess(); vgImageSubData (vgImage, source.constBits(), source.bytesPerLine(), qt_vg_image_to_vg_format(source.format()), 0, 0, w, h); source.endDataAccess(true); } recreate = false; prevSize = QSize(w, h); return vgImage; }
static void rpi_render_message(rpi_t *rpi, const char *msg) { free(rpi->mLastMsg); rpi->mLastMsg = strdup(msg); if (rpi->mMsgLength) { while (--rpi->mMsgLength) vgClearGlyph(rpi->mFont, rpi->mMsgLength); vgClearGlyph(rpi->mFont, 0); } struct font_output_list out; font_renderer_msg(rpi->mFontRenderer, msg, &out); struct font_output *head = out.head; while (head) { if (rpi->mMsgLength >= 1024) break; VGfloat origin[2], escapement[2]; VGImage img; escapement[0] = head->advance_x; escapement[1] = head->advance_y; origin[0] = -head->char_off_x; origin[1] = -head->char_off_y; img = vgCreateImage(VG_A_8, head->width, head->height, VG_IMAGE_QUALITY_NONANTIALIASED); // flip it for (unsigned i = 0; i < head->height; i++) vgImageSubData(img, head->output + head->pitch * i, head->pitch, VG_A_8, 0, head->height - i - 1, head->width, 1); vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, img, origin, escapement); vgDestroyImage(img); rpi->mMsgLength++; head = head->next; } font_renderer_free_output(&out); for (unsigned i = 0; i < rpi->mMsgLength; i++) rpi->mGlyphIndices[i] = i; }
static bool gfx_ctx_vc_image_buffer_write(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { bool ret = false; vc_ctx_data_t *vc = (vc_ctx_data_t*)data; if (!vc || index >= MAX_EGLIMAGE_TEXTURES) goto error; eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(vc->egl.dpy, vc->pbuff_surf, vc->pbuff_surf, vc->eglimage_ctx); if (!vc->eglBuffer[index] || !vc->vgimage[index]) { vc->vgimage[index] = vgCreateImage( rgb32 ? VG_sXRGB_8888 : VG_sRGB_565, vc->res, vc->res, VG_IMAGE_QUALITY_NONANTIALIASED); vc->eglBuffer[index] = peglCreateImageKHR( vc->egl.dpy, vc->eglimage_ctx, EGL_VG_PARENT_IMAGE_KHR, (EGLClientBuffer)vc->vgimage[index], NULL); ret = true; } vgImageSubData( vc->vgimage[index], frame, pitch, (rgb32 ? VG_sXRGB_8888 : VG_sRGB_565), 0, 0, width, height); *image_handle = vc->eglBuffer[index]; gfx_ctx_vc_bind_api(NULL, vc_api, 0, 0); eglMakeCurrent(vc->egl.dpy, vc->egl.surf, vc->egl.surf, vc->egl.ctx); return ret; error: *image_handle = NULL; return false; }
VGImage createImageFromRaw(const char * filename) { FILE *fp = fopen(filename, "rb"); if (!fp) { printf("File %s not found.\n", filename); } VGubyte *sourceImage; long int imageSize; fseek(fp, 0L, SEEK_END); imageSize = ftell(fp); fseek(fp, 0L, SEEK_SET); sourceImage = (VGubyte *)malloc(imageSize-8); assert(sourceImage != NULL); int *dimensions; dimensions = (int*)malloc(8); long int nrDimensionElements = fread(dimensions, 4, 2, fp); assert(nrDimensionElements == 2); fseek(fp, 8L, SEEK_SET); long int nrbytes = fread(sourceImage, 1, imageSize-8, fp); assert(nrbytes == imageSize-8); int w = dimensions[0]; int h = dimensions[1]; printf("Reading raw image with dimensions %d x %d\n", w, h); unsigned int dstride = w * 4; VGImageFormat rgbaFormat = VG_sABGR_8888; VGImage img = vgCreateImage(rgbaFormat, w, h, VG_IMAGE_QUALITY_BETTER); vgImageSubData(img, (void *)sourceImage, dstride, rgbaFormat, 0, 0, w, h); fclose(fp); free(dimensions); free(sourceImage); return img; }
VGImage QVGPixmapData::toVGImage() { if (!isValid()) return VG_INVALID_HANDLE; #if !defined(QT_NO_EGL) // Increase the reference count on the shared context. if (!context) context = qt_vg_create_context(0, QInternal::Pixmap); #endif if (recreate && prevSize != QSize(w, h)) destroyImages(); else if (recreate) cachedOpacity = -1.0f; // Force opacity image to be refreshed later. if (vgImage == VG_INVALID_HANDLE) { vgImage = QVGImagePool::instance()->createImageForPixmap (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this); // Bail out if we run out of GPU memory - try again next time. if (vgImage == VG_INVALID_HANDLE) return VG_INVALID_HANDLE; inImagePool = true; } else if (inImagePool) { QVGImagePool::instance()->useImage(this); } if (!source.isNull() && recreate) { vgImageSubData (vgImage, source.constBits(), source.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, w, h); } recreate = false; prevSize = QSize(w, h); return vgImage; }
NativeImagePtr RGBA32Buffer::asNewNativeImage() const { static const VGImageFormat bufferFormat = VG_sARGB_8888_PRE; // Save memory by using 16-bit images for fully opaque images. const VGImageFormat imageFormat = hasAlpha() ? bufferFormat : VG_sRGB_565; #if PLATFORM(EGL) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif const IntSize vgMaxImageSize(vgGeti(VG_MAX_IMAGE_WIDTH), vgGeti(VG_MAX_IMAGE_HEIGHT)); ASSERT_VG_NO_ERROR(); TiledImageOpenVG* tiledImage = new TiledImageOpenVG(IntSize(width(), height()), vgMaxImageSize); const int numColumns = tiledImage->numColumns(); const int numRows = tiledImage->numRows(); for (int yIndex = 0; yIndex < numRows; ++yIndex) { for (int xIndex = 0; xIndex < numColumns; ++xIndex) { IntRect tileRect = tiledImage->tileRect(xIndex, yIndex); VGImage image = vgCreateImage(imageFormat, tileRect.width(), tileRect.height(), VG_IMAGE_QUALITY_FASTER); ASSERT_VG_NO_ERROR(); PixelData* pixelData = const_cast<PixelData*>(m_bytes); pixelData += (tileRect.y() * width()) + tileRect.x(); vgImageSubData(image, reinterpret_cast<unsigned char*>(pixelData), width() * sizeof(PixelData), bufferFormat, 0, 0, tileRect.width(), tileRect.height()); ASSERT_VG_NO_ERROR(); tiledImage->setTile(xIndex, yIndex, image); } } return tiledImage; }
void ImageBufferData::transformColorSpace(const Vector<int>& lookUpTable) { ASSERT(m_surface); VGint width = m_surface->width(); VGint height = m_surface->height(); VGubyte* data = new VGubyte[width * height * 4]; VGubyte* currentPixel = data; if (!m_tiledImage) m_surface->makeCurrent(); if (m_surface->isCurrent()) vgReadPixels(data, width * 4, IMAGEBUFFER_VG_EXCHANGE_FORMAT, 0, 0, width, height); else vgGetImageSubData(m_tiledImage->tile(0, 0), data, width * 4, IMAGEBUFFER_VG_EXCHANGE_FORMAT, 0, 0, width, height); ASSERT_VG_NO_ERROR(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; currentPixel += 4, x++) { currentPixel[IMAGEBUFFER_A] = lookUpTable[currentPixel[IMAGEBUFFER_A]]; currentPixel[IMAGEBUFFER_R] = lookUpTable[currentPixel[IMAGEBUFFER_R]]; currentPixel[IMAGEBUFFER_G] = lookUpTable[currentPixel[IMAGEBUFFER_G]]; currentPixel[IMAGEBUFFER_B] = lookUpTable[currentPixel[IMAGEBUFFER_B]]; } } if (m_surface->isCurrent()) vgWritePixels(data, width * 4, IMAGEBUFFER_VG_EXCHANGE_FORMAT, 0, 0, width, height); else vgImageSubData(m_tiledImage->tile(0, 0), data, width * 4, IMAGEBUFFER_VG_EXCHANGE_FORMAT, 0, 0, width, height); ASSERT_VG_NO_ERROR(); delete[] data; }
int EGLUtilsVG::loadTexture(const char *fn) { char testr[256]; sprintf(testr, ":/%s", fn ); QString filename = QString( testr ); QImage image = QImage( filename ); int w=image.width(); int h=image.height(); qDebug() << filename << "w:" << w << "h:" << h; VGImage texture = vgCreateImage(VG_sARGB_8888, w, h, VG_IMAGE_QUALITY_BETTER); qDebug("vgCreateImage handle %x", texture); if(texture==VG_INVALID_HANDLE) { VGErrorCode err = vgGetError(); qDebug("loadVGImage '%s' error 0x%x", fn, err); } vgImageSubData(texture, (QRgb*)image.bits(), w*4, VG_sARGB_8888, 0, 0, w, h); return texture; }
void ImageBufferData::putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, VGImageFormat format) { ASSERT(m_surface); ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); // We expect the sourceRect to be a subset of the given source image. ASSERT(sourceRect.x() >= 0); ASSERT(sourceRect.y() >= 0); ASSERT(sourceRect.right() <= source->width()); ASSERT(sourceRect.bottom() <= source->height()); // The target origin point is the combined offset of sourceRect.location() // and destPoint. int destx = destPoint.x() + sourceRect.x(); int desty = destPoint.y() + sourceRect.y(); ASSERT(destx >= 0); ASSERT(desty >= 0); ASSERT(destx + sourceRect.width() <= size.width()); ASSERT(desty + sourceRect.height() <= size.height()); unsigned const char* data = source->data()->data()->data(); int dataOffset = (sourceRect.y() * source->width() * 4) + (sourceRect.x() * 4); if (!m_tiledImage) m_surface->makeCurrent(); if (m_surface->isCurrent()) { vgWritePixels(data + dataOffset, source->width() * 4, format, destx, desty, sourceRect.width(), sourceRect.height()); } else { vgImageSubData(m_tiledImage->tile(0, 0), data + dataOffset, source->width() * 4, format, destx, desty, sourceRect.width(), sourceRect.height()); } ASSERT_VG_NO_ERROR(); }
void SubtitleRenderer::load_glyph(char32_t codepoint) { VGfloat escapement[2]{}; auto load_glyph_internal = [&](FT_Face ft_face, VGFont vg_font, bool border) { try { auto glyph_index = FT_Get_Char_Index(ft_face, codepoint); ENFORCE(!FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_NO_HINTING)); FT_Glyph glyph; ENFORCE(!FT_Get_Glyph(ft_face->glyph, &glyph)); SCOPE_EXIT {FT_Done_Glyph(glyph);}; if (border) ENFORCE(!FT_Glyph_StrokeBorder(&glyph, ft_stroker_, 0, 1)); ENFORCE(!FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, 1)); FT_BitmapGlyph bit_glyph = (FT_BitmapGlyph) glyph; FT_Bitmap& bitmap = bit_glyph->bitmap; VGImage image{}; VGfloat glyph_origin[2]{}; if (bitmap.width > 0 && bitmap.rows > 0) { constexpr VGfloat blur_stddev = 0.6; const int padding = static_cast<int>(3*blur_stddev + 0.5); const int image_width = bitmap.width + padding*2; const int image_height = bitmap.rows + padding*2; image = vgCreateImage(VG_A_8, image_width, image_height, VG_IMAGE_QUALITY_NONANTIALIASED); assert(image); if (bitmap.pitch > 0) { vgImageSubData(image, bitmap.buffer + bitmap.pitch*(bitmap.rows-1), -bitmap.pitch, VG_A_8, padding, padding, bitmap.width, bitmap.rows); assert(!vgGetError()); } else { vgImageSubData(image, bitmap.buffer, bitmap.pitch, VG_A_8, padding, padding, bitmap.width, bitmap.rows); assert(!vgGetError()); } auto softened_image = vgCreateImage(VG_A_8, image_width, image_height, VG_IMAGE_QUALITY_NONANTIALIASED); assert(image); // Even out hard and soft edges vgGaussianBlur(softened_image, image, blur_stddev, blur_stddev, VG_TILE_FILL); assert(!vgGetError()); vgDestroyImage(image); assert(!vgGetError()); image = softened_image; glyph_origin[0] = static_cast<VGfloat>(padding - bit_glyph->left); glyph_origin[1] = static_cast<VGfloat>(padding + bitmap.rows - bit_glyph->top - 1); } escapement[0] = static_cast<VGfloat>((ft_face->glyph->advance.x + 32) / 64); escapement[1] = 0; vgSetGlyphToImage(vg_font, codepoint, image, glyph_origin, escapement); assert(!vgGetError()); if (image) { vgDestroyImage(image); assert(!vgGetError()); } } catch(...) { escapement[0] = 0; escapement[1] = 0; vgSetGlyphToImage(vg_font, codepoint, VG_INVALID_HANDLE, escapement, escapement); assert(!vgGetError()); } }; load_glyph_internal(ft_face_, vg_font_, false); glyphs_[codepoint].advance = escapement[0]; load_glyph_internal(ft_face_, vg_font_border_, true); }
void CEglTest_EGL_Image_Multi_Thread_Sibling_VGImage::doThreadFunctionL(TInt aIdx) { INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Thread_Sibling_VGImage::doThreadFunctionL, Thread %d"),aIdx); CTestEglSession* eglSess = CTestEglSession::NewLC(Logger(), iDisplay, aIdx); eglSess->InitializeL(); eglSess->OpenSgDriverL(); INFO_PRINTF2(_L("Thread %d, Creating a Surface and a Context bound to OpenVG"),aIdx); TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat); TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KPixmapSize); // Create a pixmap surface matching the native image pixel format eglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly); // Create a VGImage from the EGLImage INFO_PRINTF2(_L("Thread %d, Creating one VGImage from the shared EGLImage"),aIdx); VGImage vgImageLocal = eglSess->vgCreateImageTargetKHR((VGeglImageKHR)iEGLImageShared); ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE); Rendezvous(aIdx); if(aIdx == 0) { INFO_PRINTF2(_L("Thread %d, Updating contents of the VGImage from the shared EGLImage"),aIdx); TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat); CFbsBitmap* bitmap = eglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 8); // Add pixel data to the VGImage reference from the bitmap reference. // Mind the fact that CFbsBitmap and VGImages use different coordinates origin! TSize bitmapSize = bitmap->SizeInPixels(); TUint8* address = reinterpret_cast<TUint8*>(bitmap->DataAddress()); TInt stride = bitmap->DataStride(); address += (bitmapSize.iHeight - 1) * stride; vgImageSubData(vgImageLocal, address, -stride, KDefaultSurfaceFormat, 0,0, bitmapSize.iWidth, bitmapSize.iHeight); delete bitmap; bitmap = NULL; ASSERT_TRUE(vgGetError()==VG_NO_ERROR); eglWaitClient(); } Rendezvous(aIdx); if(aIdx == 1) { INFO_PRINTF2(_L("Thread %d, Drawing the VGImage to the current surface"),aIdx); // Copy the source VGImage to the surface vgSetPixels(0, 0, vgImageLocal, 0, 0, KPixmapSize.iWidth, KPixmapSize.iHeight); ASSERT_TRUE(vgGetError()==VG_NO_ERROR); eglWaitClient(); // we can now compare the VgImage to the one we expect after changing it in the other thread TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat); CFbsBitmap* refBitmap = eglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 8); CleanupStack::PushL(refBitmap); eglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap); CleanupStack::PopAndDestroy(refBitmap); INFO_PRINTF2(_L("Thread %d, Drawing successful"),aIdx); } // cleanup vgDestroyImage(vgImageLocal); ASSERT_TRUE(vgGetError() == VG_NO_ERROR); eglSess->CloseSgDriver(); CleanupStack::PopAndDestroy(eglSess); }
/******************************************************************************* * Function Name : InitView * Returns : true if no error occured * Description : Code in InitView() will be called by the Shell upon a change * in the rendering context. * Used to initialise variables that are dependent on the rendering * context (e.g. textures, vertex buffers, etc.) *******************************************************************************/ bool CChildImage::InitView() { //Create an image m_vgImage = vgCreateImage(VG_sRGBA_8888, IMG_SIZE, IMG_SIZE, VG_IMAGE_QUALITY_NONANTIALIASED); /* Populate the image from memory. A 32bit integer array (8bits per component) is created and populated. */ VGuint* pui32ImgData = new VGuint[IMG_SIZE*IMG_SIZE]; for(int i = 0; i < IMG_SIZE; ++i) { for(int j = 0; j < IMG_SIZE; ++j) { // Fills the data with a fancy pattern if ( ((i*j)/8) % 2 ) pui32ImgData[j*IMG_SIZE+i] = PVRTRGBA(255,255,0,255); else pui32ImgData[j*IMG_SIZE+i] = PVRTRGBA(255, 255 - (j * 2), 255 - i, 255 - (i * 2)); } } /* The data in the array is then copied to the portion of the image starting at (0,0) through to (IMG_SIZE, IMG_SIZE), in this case that is the whole image. The coordinate system of the image places (0,0) at the bottom left-hand corner and (IMG_SIZE, IMG_SIZE) at the top right-hand corner. */ vgImageSubData(m_vgImage, pui32ImgData, sizeof(VGuint) * IMG_SIZE, VG_sRGBA_8888, 0, 0, IMG_SIZE, IMG_SIZE); // Delete the image data as it is now in OpenVG memory delete[] pui32ImgData; pui32ImgData = 0; //Create child images /* The first child is a child of m_vgImage and is made up of the region of m_vgImage from (0,0) to (IMG_SIZE / 2, IMG_SIZE / 2). Note: The area specified must be in the bounds of the parent. */ m_avgChildImages[0] = vgChildImage(m_vgImage, 0, 0, (VGint) (IMG_SIZE * 0.5), (VGint) (IMG_SIZE * 0.5)); //The second child is a clone of the first child. //Get the dimensions of the first child.. int i32ChildWidth = vgGetParameteri(m_avgChildImages[0], VG_IMAGE_WIDTH); int i32ChildHeight= vgGetParameteri(m_avgChildImages[0], VG_IMAGE_HEIGHT); //..and use them to define the region for creating the second child. m_avgChildImages[1] = vgChildImage(m_avgChildImages[0], 0, 0, i32ChildWidth, i32ChildHeight); /* Clear a small portion of the bottom left-hand corner of m_avgChildImages[0] to red. This change will be seen in all relatives of m_avgChildImages[0], reason being they all share the same physical memory. Note: When clearing you specify the coordinate you want to start from and then how many pixels across and up you want to clear. */ VGfloat afClearColour[] = {1.0f, 0.0f, 0.0f, 1.0f}; vgSetfv(VG_CLEAR_COLOR, 4, afClearColour); vgClearImage(m_avgChildImages[0], 0, 0, 10, 10); //Set the clear colour for clearing the sceen afClearColour[0] = 0.6f; afClearColour[1] = 0.8f; afClearColour[2] = 1.0f; afClearColour[3] = 1.0f; vgSetfv(VG_CLEAR_COLOR, 4, afClearColour); m_PrintVG.Initialize(PVRShellGet(prefWidth), PVRShellGet(prefHeight)); return true; }
/** Overridden function, which creates Open VG images for foreground, background, shadow and outline components of the font. @param aGlyphImage Source bitmap data in 256 grey format. Each pixel value is an index to a constant lookup table. Four entries of this table represent % of Outline, Shadow, Fill and Background colour to be used to get the final colour to be displayed on screen. @param aGlyphImageSize Size of the glyph bitmap image. @param aForeground Foreground component of the glyph. @param aOutline Outline component of the glyph. @param aShadow Shadow component of the glyph. @param aPreAllocForeground Pre-allocated buffer which will be used for setting text foreground VG image @param aPreAllocOutline Pre-allocated buffer which will be used for setting text outline VG image @param aPreAllocShadow Pre-allocated buffer which will be used for setting text shadow VG image @post Requested OpenVG images are ready for rendering. */ void CFontGlyphTree::CreateVGImageL(const TUint8* aGlyphImage, const TSize& aGlyphImageSize, VGImage& aForeground, VGImage& aOutline, VGImage& aShadow, TUint8* aPreAllocForeground, TUint8* aPreAllocOutline, TUint8* aPreAllocShadow) { TInt dataStride = aGlyphImageSize.iWidth; TInt targetByteCount = dataStride * aGlyphImageSize.iHeight; // Allocate memory and transform source into target format. // TAny* foregroundBuffer = NULL; TAny* outlineBuffer = NULL; TAny* shadowBuffer = NULL; TBool destroyTempBuffer = EFalse; if(aPreAllocForeground && aPreAllocOutline && aPreAllocShadow && (aGlyphImageSize.iWidth <= KMaxSizeImageOOM.iWidth) && (aGlyphImageSize.iHeight <= KMaxSizeImageOOM.iHeight)) { foregroundBuffer = aPreAllocForeground; outlineBuffer = aPreAllocOutline; shadowBuffer = aPreAllocShadow; } else { foregroundBuffer = User::AllocL(targetByteCount); CleanupStack::PushL(foregroundBuffer); outlineBuffer = User::AllocL(targetByteCount); CleanupStack::PushL(outlineBuffer); shadowBuffer = User::AllocL(targetByteCount); CleanupStack::PushL(shadowBuffer); destroyTempBuffer = ETrue; } TUint8* foregroundByte = static_cast <TUint8*> (foregroundBuffer); TUint8* outlineByte = static_cast <TUint8*> (outlineBuffer); TUint8* shadowByte = static_cast <TUint8*> (shadowBuffer); const TUint8* endByte = (TUint8*)aGlyphImage + targetByteCount; TUint8* curSrcGlyphImage = const_cast <TUint8*> (aGlyphImage); while (curSrcGlyphImage < endByte) { *outlineByte++ = FourColorBlendLookup[*curSrcGlyphImage] [KOutlineColorIndex]; *shadowByte++ = FourColorBlendLookup[*curSrcGlyphImage] [KShadowColorIndex]; *foregroundByte++ = FourColorBlendLookup[*curSrcGlyphImage] [KFillColorIndex]; curSrcGlyphImage++; } const VGImageFormat imageFormat = VG_sL_8; if(aForeground == VG_INVALID_HANDLE) { aForeground = vgCreateImage(imageFormat, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED); if(aForeground == VG_INVALID_HANDLE) { User::Leave(KErrNoMemory); } aOutline = vgCreateImage(imageFormat, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED); if(aOutline == VG_INVALID_HANDLE) { DestroyVGImage(&aForeground); User::Leave(KErrNoMemory); } aShadow = vgCreateImage(imageFormat, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED); if(aShadow == VG_INVALID_HANDLE) { DestroyVGImage(&aForeground, &aOutline); User::Leave(KErrNoMemory); } } vgImageSubData( aForeground, foregroundBuffer, dataStride, imageFormat, 0, 0,aGlyphImageSize.iWidth, aGlyphImageSize.iHeight); #ifdef DRAWGLYPH_MULTIPLY_MODE VGImage image = vgCreateImage(VG_sARGB_8888_PRE, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED); vgColorMatrix(image, aForeground, KColorMatrix); vgDestroyImage(aForeground); aForeground = image; #endif // DRAWGLYPH_MULTIPLY_MODE vgImageSubData( aOutline, outlineBuffer, dataStride, imageFormat, 0, 0, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight); #ifdef DRAWGLYPH_MULTIPLY_MODE image = vgCreateImage(VG_sARGB_8888_PRE, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED); vgColorMatrix(image, aOutline, KColorMatrix); vgDestroyImage(aOutline); aOutline = image; #endif // DRAWGLYPH_MULTIPLY_MODE vgImageSubData( aShadow, shadowBuffer, dataStride, imageFormat, 0, 0, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight); #ifdef DRAWGLYPH_MULTIPLY_MODE image = vgCreateImage(VG_sARGB_8888_PRE, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED); vgColorMatrix(image, aShadow, KColorMatrix); vgDestroyImage(aShadow); aShadow = image; #endif // DRAWGLYPH_MULTIPLY_MODE if(destroyTempBuffer) { CleanupStack::PopAndDestroy(3, foregroundBuffer); } }
/** Overridden function, which creates OpenVG images for monochrome and anti-aliased fonts. @param aGlyphImage Data source bitmap in 256 or 2 Grey format. @param aGlyphImageSize Glyph image data size. @param aDisplayMode Image display mode. @param aForeground Foreground component of the glyph. @param aPreAllocForeground Pre-allocated buffer which will be used for setting foreground VG image @post Requested OpenVG image is ready for rendering. @panic Panic if bitmap display mode is not 256 grey or 2 grey. */ void CFontGlyphTree::CreateVGImageL(const TUint8* aGlyphImage, const TSize& aGlyphImageSize, TDisplayMode aDisplayMode, VGImage& aForeground, TUint8* aPreAllocForeground) { GRAPHICS_ASSERT_DEBUG((aDisplayMode == EGray256) || (aDisplayMode == EGray2), EDirectGdiPanicInvalidDisplayMode); GRAPHICS_ASSERT_DEBUG(aGlyphImage, EDirectGdiPanicInvalidParameter); VGImageFormat imageFormat = VG_IMAGE_FORMAT_INVALID; TInt vgCompatibleSourceStride = 0x00; TUint32 binaryDataArray[32]; TUint8* binaryData = NULL; TUint8* tempBuffer = NULL; if(aDisplayMode == EGray256) { imageFormat = VG_sL_8; vgCompatibleSourceStride = aGlyphImageSize.iWidth; binaryData = const_cast <TUint8*> (aGlyphImage); } else //EGray2 { imageFormat = VG_BW_1; vgCompatibleSourceStride = ((aGlyphImageSize.iWidth + 31) / 32) << 2; if (aGlyphImageSize.iWidth > 30 || aGlyphImageSize.iHeight > 32) { binaryData = aPreAllocForeground; if(!binaryData) { tempBuffer = (TUint8*) User::AllocL(vgCompatibleSourceStride * aGlyphImageSize.iHeight); CleanupStack::PushL(tempBuffer); binaryData = tempBuffer; } DecodeBinaryDataExLarge(aGlyphImageSize, aGlyphImage, vgCompatibleSourceStride, reinterpret_cast <TUint32*> (binaryData)); } else { DecodeBinaryData(aGlyphImageSize, aGlyphImage, binaryDataArray); binaryData = reinterpret_cast <TUint8*> (binaryDataArray); } } if(aForeground == VG_INVALID_HANDLE) { aForeground = vgCreateImage(imageFormat, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED); } if (aForeground != VG_INVALID_HANDLE) { // Copy from the source image to our new VGImage vgImageSubData(aForeground, binaryData, vgCompatibleSourceStride, imageFormat, 0, 0, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight); #ifdef DRAWGLYPH_MULTIPLY_MODE VGImage image = vgCreateImage(VG_sARGB_8888_PRE, aGlyphImageSize.iWidth, aGlyphImageSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED); vgColorMatrix(image, aForeground, KColorMatrix); vgDestroyImage(aForeground); aForeground = image; #endif } else { if(tempBuffer) { CleanupStack::PopAndDestroy(tempBuffer); } User::Leave(KErrNoMemory); } if(tempBuffer) { CleanupStack::PopAndDestroy(tempBuffer); } }
/******************************************************************************* * Function Name : InitView * Returns : true if no error occured * Description : Code in InitView() will be called by the Shell upon a change * in the rendering context. * Used to initialise variables that are dependent on the rendering * context (e.g. textures, vertex buffers, etc.) *******************************************************************************/ bool CImage::InitView() { //Create a pair of images m_avgImage[0] = vgCreateImage(VG_sRGBA_8888, IMG_SIZE, IMG_SIZE, VG_IMAGE_QUALITY_NONANTIALIASED); m_avgImage[1] = vgCreateImage(VG_sRGBA_8888, IMG_SIZE, IMG_SIZE, VG_IMAGE_QUALITY_NONANTIALIASED); /* The first image will be populated from memory. A 32bit integer array (8bits per component) is created and populated. */ VGuint* pui32ImgData = new VGuint[IMG_SIZE * IMG_SIZE]; for (int i = 0; i < IMG_SIZE; ++i) { for (int j = 0; j < IMG_SIZE; ++j) { // Fills the data with a fancy pattern if ( ((i*j)/8) % 2 ) pui32ImgData[j*IMG_SIZE+i] = PVRTRGBA(255,255,0,255); else pui32ImgData[j*IMG_SIZE+i] = PVRTRGBA(255, 255 - (j * 2), 255 - i, 255 - (i * 2)); } } /* The data in the array is then copied to the portion of the image starting at (0,0) through to (IMG_SIZE, IMG_SIZE), in this case that is the whole image. The coordinate system of the image places (0,0) at the bottom left-hand corner and (IMG_SIZE, IMG_SIZE) at the top right-hand corner. */ vgImageSubData(m_avgImage[0],pui32ImgData, sizeof(VGuint) * IMG_SIZE,VG_sRGBA_8888, 0, 0, IMG_SIZE, IMG_SIZE); // Delete the image data as it is now in OpenVG memory delete[] pui32ImgData; pui32ImgData = 0; /* The second image will initially be cleared to a single colour and then a part of the first image will be copied to it. */ //The colour to clear the image to is taken from the currently set VG_CLEAR_COLOR. VGfloat afClearColour[] = { 1.0f, 0.8f, 0.6f, 1.0f }; vgSetfv(VG_CLEAR_COLOR, 4, afClearColour); //Clear the part of the image in the range (0,0) to (IMG_SIZE, IMG_SIZE), in this case that is the whole image. vgClearImage(m_avgImage[1], 0, 0, IMG_SIZE, IMG_SIZE); /* Copy the bottom left-hand corner ((0,0) to (IMG_SIZE / 2, IMG_SIZE / 2)) of the first image into the the second image starting at (IMG_SIZE / 4, IMG_SIZE / 4). */ int i32ImgSizeQuarter = (int) (IMG_SIZE * 0.25); vgCopyImage(m_avgImage[1], i32ImgSizeQuarter, i32ImgSizeQuarter, m_avgImage[0], 0,0, (VGint) (IMG_SIZE * 0.5), (VGint) (IMG_SIZE * 0.5), (VGboolean) false); //Set the clear colour for clearing the sceen afClearColour[0] = 0.6f; afClearColour[1] = 0.8f; afClearColour[2] = 1.0f; afClearColour[3] = 1.0f; vgSetfv(VG_CLEAR_COLOR, 4, afClearColour); m_PrintVG.Initialize(PVRShellGet(prefWidth), PVRShellGet(prefHeight)); return true; }
// createImageFromJpeg decompresses a JPEG image to the standard image format // source: https://github.com/ileben/ShivaVG/blob/master/examples/test_image.c VGImage createImageFromJpeg(const char *filename) { FILE *infile; struct jpeg_decompress_struct jdc; struct jpeg_error_mgr jerr; JSAMPARRAY buffer; unsigned int bstride; unsigned int bbpp; VGImage img; VGubyte *data; unsigned int width; unsigned int height; unsigned int dstride; unsigned int dbpp; VGubyte *brow; VGubyte *drow; unsigned int x; unsigned int lilEndianTest = 1; VGImageFormat rgbaFormat; // Check for endianness if (((unsigned char *)&lilEndianTest)[0] == 1) rgbaFormat = VG_sABGR_8888; else rgbaFormat = VG_sRGBA_8888; // Try to open image file infile = fopen(filename, "rb"); if (infile == NULL) { printf("Failed opening '%s' for reading!\n", filename); return VG_INVALID_HANDLE; } // Setup default error handling jdc.err = jpeg_std_error(&jerr); jpeg_create_decompress(&jdc); // Set input file jpeg_stdio_src(&jdc, infile); // Read header and start jpeg_read_header(&jdc, TRUE); jpeg_start_decompress(&jdc); width = jdc.output_width; height = jdc.output_height; // Allocate buffer using jpeg allocator bbpp = jdc.output_components; bstride = width * bbpp; buffer = (*jdc.mem->alloc_sarray) ((j_common_ptr) & jdc, JPOOL_IMAGE, bstride, 1); // Allocate image data buffer dbpp = 4; dstride = width * dbpp; data = (VGubyte *) malloc(dstride * height); // Iterate until all scanlines processed while (jdc.output_scanline < height) { // Read scanline into buffer jpeg_read_scanlines(&jdc, buffer, 1); drow = data + (height - jdc.output_scanline) * dstride; brow = buffer[0]; // Expand to RGBA for (x = 0; x < width; ++x, drow += dbpp, brow += bbpp) { switch (bbpp) { case 4: drow[0] = brow[0]; drow[1] = brow[1]; drow[2] = brow[2]; drow[3] = brow[3]; break; case 3: drow[0] = brow[0]; drow[1] = brow[1]; drow[2] = brow[2]; drow[3] = 255; break; } } } // Create VG image img = vgCreateImage(rgbaFormat, width, height, VG_IMAGE_QUALITY_BETTER); vgImageSubData(img, data, dstride, rgbaFormat, 0, 0, width, height); // Cleanup jpeg_destroy_decompress(&jdc); fclose(infile); free(data); return img; }
void CTReadWriteChild::WriteImageFuncL() { vgImageSubData(iImage, iData, iWidth*iByteSize, iFormat, 0, 0, iWidth, iHeight); VgLeaveIfErrorL(); }
int createFont(FT_Face fontFace, FT_UInt size) { initFreeTypeLibrary(); VGfloat glyphOrigin[2]; VGfloat escapement[2]; FT_Stroker fontStroker; int error = FT_Stroker_New(freeTypeLibrary, &fontStroker); if (error) { logInfo(LOG_FREETYPE, "Error FT_Stroker_New.(error=%d)\n", error); return -1; } FT_Stroker_Set(fontStroker, 2*64.0f, // Need to get the right value based on size. FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); VGFont tmpFont; struct fontListItem *tmpFontListItem = fontExists(fontFace, size); if (tmpFontListItem == NULL) { tmpFont = vgCreateFont(fontFace->num_glyphs); if (tmpFont == VG_INVALID_HANDLE) { logInfo(LOG_FREETYPE, "Error could not create vgCreateFont.\n"); return -1; } tmpFontListItem = malloc(sizeof(struct fontListItem)); tmpFontListItem->fontFace = fontFace; tmpFontListItem->size = size; tmpFontListItem->font = tmpFont; addToFontList(tmpFontListItem); } else { return 0; } error = FT_Set_Char_Size( fontFace, /* handle to face object */ 0, /* char_width in 1/64th of points */ size*64, /* char_height in 1/64th of points */ 72, /* horizontal device resolution */ 72 ); /* vertical device resolution */ if (error) { logInfo(LOG_FREETYPE, "Error FT_Set_Char_Size.(error=%d)\n", error); return -1; } int index; int counter = 0; FT_UInt charIndex; VGImage image = VG_INVALID_HANDLE; VGImage softenedImage; VGfloat blustStdDev; int padding; int image_width; int image_height; VGErrorCode vg_error; FT_Glyph glyph; logInfo(LOG_FREETYPE, "This font contains %ld glyphs.\n", fontFace->num_glyphs); for (index = 32; (index < 256) && (counter < fontFace->num_glyphs); index++) { counter++; charIndex = FT_Get_Char_Index(fontFace, index); logInfo(LOG_FREETYPE, "index=0x%x, charIndex=0x%x\n", index, charIndex); escapement[0] = 0; escapement[1] = 0; if (charIndex == 0) { vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "charindex== 0\n"); continue; } error = FT_Load_Glyph(fontFace, charIndex, FT_LOAD_NO_HINTING); if (error) { vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "Error FT_Load_Glyph (error:%d)\n", error); continue; } error = FT_Get_Glyph(fontFace->glyph, &glyph); if (error) { vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "Error FT_Get_Glyph (error:%d)\n", error); continue; } /* error = FT_Glyph_StrokeBorder(&glyph, fontStroker, 0, 1); if (error) { FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "Error FT_Glyph_StrokeBorder (error:%d)\n", error); continue; } */ error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, 1); if (error) { FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "Error FT_Glyph_To_Bitmap (error:%d)\n", error); continue; } FT_BitmapGlyph bitGlyph = (FT_BitmapGlyph)glyph; FT_Bitmap bitmap = bitGlyph->bitmap; if (bitmap.width > 0 && bitmap.rows > 0) { blustStdDev = 0.6; padding = (3*blustStdDev + 0.5); image_width = bitmap.width + padding*2; image_height = bitmap.rows + padding*2; image = vgCreateImage(VG_A_8, image_width, image_height, VG_IMAGE_QUALITY_NONANTIALIASED); if (image == VG_INVALID_HANDLE) { FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "vgCreateImage (error:%d)\n", vgGetError()); continue; } if (bitmap.pitch > 0) { vgImageSubData(image, bitmap.buffer + bitmap.pitch*(bitmap.rows-1), -bitmap.pitch, VG_A_8, padding, padding, bitmap.width, bitmap.rows); } else { vgImageSubData(image, bitmap.buffer, bitmap.pitch, VG_A_8, padding, padding, bitmap.width, bitmap.rows); } vg_error = vgGetError(); if (vg_error) { vgDestroyImage(image); FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); showVGErrorStr(vg_error, "vgImageSubData"); continue; } softenedImage = vgCreateImage(VG_A_8, image_width, image_height, VG_IMAGE_QUALITY_NONANTIALIASED); if (softenedImage == VG_INVALID_HANDLE) { vgDestroyImage(image); FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); logInfo(LOG_FREETYPE, "vgCreateImage (error:%d)\n", vgGetError()); continue; } // Even out hard and soft edges vgGaussianBlur(softenedImage, image, blustStdDev, blustStdDev, VG_TILE_FILL); vg_error = vgGetError(); if (vg_error) { vgDestroyImage(softenedImage); vgDestroyImage(image); FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); showVGErrorStr(vg_error, "vgGaussianBlur"); continue; } vgDestroyImage(image); image = softenedImage; glyphOrigin[0] = (VGfloat)(padding - bitGlyph->left); glyphOrigin[1] = (VGfloat)(padding + bitmap.rows - bitGlyph->top - 1); } else { logInfo(LOG_FREETYPE, "Error bitmap.width = %d, bitmap.rows = %d\n", bitmap.width, bitmap.rows); } escapement[0] = (VGfloat)((fontFace->glyph->advance.x + 32) / 64); escapement[1] = 0; vgSetGlyphToImage(tmpFont, index, image, glyphOrigin, escapement); vg_error = vgGetError(); if (vg_error) { vgDestroyImage(softenedImage); vgDestroyImage(image); FT_Done_Glyph(glyph); vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement); showVGErrorStr(vg_error, "vgSetGlyphToImage"); continue; } logInfo(LOG_FREETYPE, "Create glyph %d.\n", index); FT_Done_Glyph(glyph); if (image != VG_INVALID_HANDLE) { vgDestroyImage(image); } } return 0; }