void SimpleSurface::applyFilter (Surface *inSrc, const Rect &inRect, ImagePoint inOffset, Filter *inFilter) { if (!mBase) return; FilterList f; f.push_back (inFilter); Rect src_rect (inRect.w, inRect.h); Rect dest = GetFilteredObjectRect (f, src_rect); inSrc->IncRef (); Surface *result = FilterBitmap (f, inSrc, src_rect, dest, false, ImagePoint (inRect.x, inRect.y)); dest.Translate (inOffset.x, inOffset.y); src_rect = Rect (0, 0, result->Width (), result->Height ()); int dx = dest.x; int dy = dest.y; dest = dest.Intersect (Rect (0, 0, mWidth, mHeight)); dest.Translate (-dx, -dy); dest = dest.Intersect (src_rect); dest.Translate (dx, dy); int bpp = BytesPP (); RenderTarget t = BeginRender (dest, false); //printf("Copy back @ %d,%d %dx%d + (%d,%d)\n", dest.x, dest.y, t.Width(), t.Height(), dx, dy); for (int y = 0; y < t.Height (); y++) memcpy ((void *)(t.Row (y + dest.y) + ((dest.x) * bpp)), result->Row (y - dy) - (dx * bpp), dest.w * bpp); EndRender (); result->DecRef (); }
void RenderGlyph(int inChar,const RenderTarget &outTarget) { if (!LoadBitmap(inChar)) return; FT_Bitmap &bitmap = mFace->glyph->bitmap; int w = bitmap.width; int h = bitmap.rows; if (w>outTarget.mRect.w || h>outTarget.mRect.h) return; for(int r=0; r<h; r++) { unsigned char *row = bitmap.buffer + r*bitmap.pitch; uint8 *dest = (uint8 *)outTarget.Row(r + outTarget.mRect.y) + outTarget.mRect.x; if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { int bit = 0; int data = 0; for(int x=0; x<outTarget.mRect.w; x++) { if (!bit) { bit = 128; data = *row++; } *dest++ = (data & bit) ? 0xff: 0x00; bit >>= 1; } } else if (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
void AlphaMask::RenderBitmap(int inTX, int inTY, const RenderTarget &inTarget, const RenderState &inState) { if (mLineStarts.size() < 2) return; Rect clip = inState.mClipRect; int y = mRect.y + inTY; const int *start = &mLineStarts[0] - y; int y1 = mRect.y1() + inTY; clip.ClipY(y, y1); for (; y < y1; y++) { const AlphaRun *end = &mAlphaRuns[start[y + 1]]; const AlphaRun *run = &mAlphaRuns[start[y]]; if (run != end) { Uint8 *dest0 = inTarget.Row(y); while (run < end && run->mX1 + inTX <= clip.x) run++; while (run < end) { int x0 = run->mX0 + inTX; if (x0 >= clip.x1()) break; int x1 = run->mX1 + inTX; clip.ClipX(x0, x1); Uint8 *dest = dest0 + x0; int alpha = run->mAlpha; if (alpha > 0) { if (alpha >= 255) { while (x0++ < x1) *dest++ = 255; } else { while(x0++ < x1) QBlendAlpha(*dest++, alpha); } } ++run; } } } }
void RenderGlyph(int inChar,const RenderTarget &outTarget) { if (!LoadBitmap(inChar)) return; int underlineY0 = -1; int underlineY1 = -1; FT_Bitmap &bitmap = mFace->glyph->bitmap; int w = bitmap.width; int h = bitmap.rows; if (mTransform & ffUnderline) { underlineY0 = mFace->glyph->bitmap_top + getUnderlineOffset(); underlineY1 = underlineY0 + getUnderlineHeight(); } if (h<underlineY1) h = underlineY1; if (w>outTarget.mRect.w || h>outTarget.mRect.h) return; for(int r=0;r<h;r++) { uint8 *dest = (uint8 *)outTarget.Row(r + outTarget.mRect.y) + outTarget.mRect.x; int underline = (r>=underlineY0 && r<underlineY1) ? 0xff : 0; if (r<bitmap.rows) { unsigned char *row = bitmap.buffer + r*bitmap.pitch; if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { int bit = 0; int data = 0; for(int x=0;x<outTarget.mRect.w;x++) { if (!bit) { bit = 128; data = *row++; } *dest++ = (underline || (data & bit)) ? 0xff: 0x00; bit >>= 1; } } else if (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
void RenderGlyph(int inChar, const RenderTarget &outTarget) { if (!sGammaLUTInit) { double pow_max = 255.0/pow(255,1.9); for(int i=0;i<256;i++) { sGammaLUT[i] = pow(i,1.9)*pow_max + 0.5; } sGammaLUTInit = true; } int w = outTarget.mRect.w; w = (w+3) & ~3; int h = outTarget.mRect.h; if (w>sgDIB_W || h>sgDIB_H) { if (sgDIB) { SelectObject(sgFontDC,sgOldDIB); DeleteObject(sgDIB); } BITMAPINFO bmi; memset(&bmi,0,sizeof(bmi)); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = w; bmi.bmiHeader.biHeight = h; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; sgDIB_W = w; sgDIB_H = h; sgDIB = CreateDIBSection(sgFontDC,&bmi,DIB_RGB_COLORS, (void **)&sgDIBBits, 0, 0 ); sgOldDIB = (HBITMAP)SelectObject(sgFontDC,sgDIB); } memset(sgDIBBits,0,sgDIB_W*sgDIB_H*4); wchar_t ch = inChar; TextOutW(sgFontDC,0,0,&ch,1); for(int y=0;y<outTarget.mRect.h;y++) { ARGB *src = sgDIBBits + (sgDIB_H - 1 - y)*sgDIB_W; uint8 *dest = (uint8 *)outTarget.Row(y + outTarget.mRect.y) + outTarget.mRect.x; for(int x=0;x<outTarget.mRect.w;x++) *dest++= sGammaLUT[(src++)->g]; } }
bool PointRenderer::Render( const RenderTarget &inTarget, const RenderState &inState ) { Extent2DF extent; CachedExtentRenderer::GetExtent(inState.mTransform,extent); if (!extent.Valid()) return true; // Get bounding pixel rect Rect rect = inState.mTransform.GetTargetRect(extent); // Intersect with clip rect ... Rect visible_pixels = rect.Intersect(inState.mClipRect); int x0 = visible_pixels.x; int y0 = visible_pixels.y; int x1 = visible_pixels.x1(); int y1 = visible_pixels.y1(); bool swap = gC0IsRed != (bool)(inTarget.mPixelFormat & pfSwapRB); //bool alpha = (inTarget.mPixelFormat & pfHasAlpha); if (!mHasColours) { int val = swap ? mCol.SwappedIVal() : mCol.ival; // 100% alpha... if ( ( (val & 0xff000000) == 0xff000000 ) || (inTarget.mPixelFormat & pfHasAlpha) ) { for(int i=0; i<mTransformed.size(); i++) { const UserPoint &point = mTransformed[i]; int tx = point.x; if (x0<=tx && tx<x1) { int ty = point.y; if (y0<=ty && ty<y1) ((int *)inTarget.Row(ty))[tx] = val; } } } else { ARGB argb = swap ? mCol.Swapped() : mCol; for(int i=0; i<mTransformed.size(); i++) { const UserPoint &point = mTransformed[i]; int tx = point.x; if (x0<=tx && tx<x1) { int ty = point.y; if (y0<=ty && ty<y1) ((ARGB *)inTarget.Row(ty))[tx].QBlendA(argb); } } } } else { ARGB *argb = (ARGB *) & mData[mData0 + mTransformed.size()*2]; if (inTarget.mPixelFormat & pfHasAlpha) for(int i=0; i<mTransformed.size(); i++) { const UserPoint &point = mTransformed[i]; int tx = point.x; if (x0<=tx && tx<x1) { int ty = point.y; if (y0<=ty && ty<y1) ((ARGB *)inTarget.Row(ty))[tx].QBlendA( swap? argb[i] : argb[i].Swapped() ); } } else for(int i=0; i<mTransformed.size(); i++) { const UserPoint &point = mTransformed[i]; int tx = point.x; if (x0<=tx && tx<x1) { int ty = point.y; if (y0<=ty && ty<y1) ((ARGB *)inTarget.Row(ty))[tx].QBlend( swap? argb[i].Swapped() : argb[i] ); } } } return true; }
void SimpleSurface::BlitChannel (const RenderTarget &outTarget, const Rect &inSrcRect, int inPosX, int inPosY, int inSrcChannel, int inDestChannel) const { bool src_alpha = (mPixelFormat == pfAlpha); bool dest_alpha = (outTarget.mPixelFormat == pfAlpha); // Flash API does not have alpha images (might be useful somewhere else?) if (src_alpha || dest_alpha) return; if (inDestChannel == CHAN_ALPHA && !(outTarget.Format () & pfHasAlpha)) return; bool set_255 = (inSrcChannel == CHAN_ALPHA && !(mPixelFormat & pfHasAlpha)); // Translate inSrcRect src_rect to dest ... Rect src_rect (inPosX, inPosY, inSrcRect.w, inSrcRect.h); // clip ... src_rect = src_rect.Intersect (outTarget.mRect); // translate back to source-coordinates ... src_rect.Translate (inSrcRect.x - inPosX, inSrcRect.y - inPosY); // clip to origial rect... src_rect = src_rect.Intersect (inSrcRect); if (src_rect.HasPixels ()) { int dx = inPosX + src_rect.x; int dy = inPosY + src_rect.y; bool c0_red = gC0IsRed != ((mPixelFormat & pfSwapRB) != 0); int src_ch = (inSrcChannel == CHAN_ALPHA ? 3 : inSrcChannel == CHAN_BLUE ? (c0_red ? 2 : 0) : inSrcChannel == CHAN_GREEN ? 1 : (c0_red ? 0 : 2)); c0_red = gC0IsRed != ((outTarget.Format () & pfSwapRB) != 0); int dest_ch = (inDestChannel == CHAN_ALPHA ? 3 : inDestChannel == CHAN_BLUE ? (c0_red ? 2 : 0) : inDestChannel == CHAN_GREEN ? 1 : (c0_red ? 0 : 2)); for (int y = 0; y < src_rect.h; y++) { uint8 *d = outTarget.Row (y + dy) + (dx * 4) + dest_ch; if (set_255) { for (int x = 0; x < src_rect.w; x++) { *d = 255; d += 4; } } else { const uint8 *s = Row (y + src_rect.y) + (src_rect.x * 4) + src_ch; for(int x = 0; x < src_rect.w; x++) { *d = *s; d += 4; s += 4; } } } } }
static Surface *TryPNG(FILE *inFile,const uint8 *inData, int inDataLen) { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, user_error_fn, user_warning_fn); if (png_ptr == NULL) return (0); /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (0); } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ Surface *result = 0; RenderTarget target; if (setjmp(png_jmpbuf(png_ptr))) { if (result) { result->EndRender(); result->DecRef(); } /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* If we get here, we had a problem reading the file */ return (0); } ReadBuf buffer(inData,inDataLen); if (inFile) { png_init_io(png_ptr, inFile); } else { png_set_read_fn(png_ptr,(void *)&buffer, user_read_data_fn); } png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); bool has_alpha = color_type== PNG_COLOR_TYPE_GRAY_ALPHA || color_type==PNG_COLOR_TYPE_RGB_ALPHA || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); /* Add filler (or alpha) byte (before/after each RGB triplet) */ png_set_expand(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); //png_set_gray_1_2_4_to_8(png_ptr); png_set_palette_to_rgb(png_ptr); png_set_gray_to_rgb(png_ptr); // Stripping 16 bits per channel to 8 bits per channel. if (bit_depth == 16) png_set_strip_16(png_ptr); png_set_bgr(png_ptr); result = new SimpleSurface(width,height, (has_alpha) ? pfARGB : pfXRGB); result->IncRef(); target = result->BeginRender(Rect(width,height)); /* if the image is interlaced, run multiple passes */ int number_of_passes = png_set_interlace_handling(png_ptr); for (int pass = 0; pass < number_of_passes; pass++) { for (int i = 0; i < height; i++) { png_bytep anAddr = (png_bytep) target.Row(i); png_read_rows(png_ptr, (png_bytepp) &anAddr, NULL, 1); } } result->EndRender(); /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* that's it */ return result; }
static Surface *TryJPEG(FILE *inFile,const uint8 *inData, int inDataLen) { struct jpeg_decompress_struct cinfo; // Don't exit on error! struct ErrorData jpegError; cinfo.err = jpeg_std_error(&jpegError.base); jpegError.base.error_exit = OnError; jpegError.base.output_message = OnOutput; Surface *result = 0; uint8 *row_buf = 0; // Establish the setjmp return context for ErrorFunction to use if (setjmp(jpegError.on_error)) { if (row_buf) free(row_buf); if (result) result->DecRef(); jpeg_destroy_decompress(&cinfo); return 0; } // Initialize the JPEG decompression object. jpeg_create_decompress(&cinfo); // Specify data source (ie, a file, or buffer) MySrcManager manager(inData,inDataLen); if (inFile) jpeg_stdio_src(&cinfo, inFile); else { cinfo.src = &manager.pub; } // Read file parameters with jpeg_read_header(). if (jpeg_read_header(&cinfo, TRUE)!=JPEG_HEADER_OK) return 0; cinfo.out_color_space = JCS_RGB; // Start decompressor. jpeg_start_decompress(&cinfo); result = new SimpleSurface(cinfo.output_width, cinfo.output_height, pfXRGB); result->IncRef(); RenderTarget target = result->BeginRender(Rect(cinfo.output_width, cinfo.output_height)); row_buf = (uint8 *)malloc(cinfo.output_width * 3); while (cinfo.output_scanline < cinfo.output_height) { uint8 * src = row_buf; uint8 * dest = target.Row(cinfo.output_scanline); jpeg_read_scanlines(&cinfo, &row_buf, 1); uint8 *end = dest + cinfo.output_width*4; while (dest<end) { dest[0] = src[2]; dest[1] = src[1]; dest[2] = src[0]; dest[3] = 0xff; dest+=4; src+=3; } } result->EndRender(); free(row_buf); // Finish decompression. jpeg_finish_decompress(&cinfo); // Release JPEG decompression object jpeg_destroy_decompress(&cinfo); return result; }
Tile Font::GetGlyph(int inCharacter,int &outAdvance) { bool use_default = false; Glyph &glyph = inCharacter < 128 ? mGlyph[inCharacter] : mExtendedGlyph[inCharacter]; if (glyph.sheet<0) { int gw,gh,adv,ox,oy; bool ok = mFace->GetGlyphInfo(inCharacter,gw,gh,adv,ox,oy); if (!ok) { if (inCharacter=='?') { gw = mPixelHeight; gh = mPixelHeight; ox = oy = 0; adv = mPixelHeight; use_default = true; } else { Tile result = GetGlyph('?',outAdvance); glyph = mGlyph['?']; return result; } } int orig_w = gw; int orig_h = gh; switch(mRotation) { case gr270: std::swap(gw,gh); std::swap(ox,oy); oy = -gh-oy; break; case gr180: ox = -gw-ox; oy = -gh-oy; break; case gr90: std::swap(gw,gh); std::swap(ox,oy); ox = -gw-ox; break; } while(1) { // Allocate new sheet? if (mCurrentSheet<0) { int rows = mPixelHeight > 128 ? 1 : mPixelHeight > 64 ? 2 : mPixelHeight>32 ? 4 : 5; int h = 4; while(h<mPixelHeight*rows) h*=2; int w = h; while(w<orig_w) w*=2; if (mRotation!=gr0 && mRotation!=gr180) std::swap(w,h); Tilesheet *sheet = new Tilesheet(w,h,pfAlpha,true); mCurrentSheet = mSheets.size(); mSheets.push_back(sheet); } int tid = mSheets[mCurrentSheet]->AllocRect(gw,gh,ox,oy); if (tid>=0) { glyph.sheet = mCurrentSheet; glyph.tile = tid; glyph.advance = adv; break; } // Need new sheet... mCurrentSheet = -1; } // Now fill rect... Tile tile = mSheets[glyph.sheet]->GetTile(glyph.tile); // SharpenText(bitmap); RenderTarget target = tile.mSurface->BeginRender(tile.mRect); if (use_default) { for(int y=0; y<target.mRect.h; y++) { uint8 *dest = (uint8 *)target.Row(y + target.mRect.y) + target.mRect.x; for(int x=0; x<target.mRect.w; x++) *dest++ = 0xff; } } else if (mRotation==gr0) mFace->RenderGlyph(inCharacter,target); else { SimpleSurface *buf = new SimpleSurface(orig_w,orig_h,pfAlpha,true); buf->IncRef(); { AutoSurfaceRender renderer(buf); mFace->RenderGlyph(inCharacter,renderer.Target()); } const uint8 *src; for(int y=0; y<target.mRect.h; y++) { uint8 *dest = (uint8 *)target.Row(y + target.mRect.y) + target.mRect.x; switch(mRotation) { case gr270: src = buf->Row(0) + buf->Width() -1 - y; for(int x=0; x<target.mRect.w; x++) { *dest++ = *src; src += buf->GetStride(); } break; case gr180: src = buf->Row(buf->Height()-1-y) + buf->Width() -1; for(int x=0; x<target.mRect.w; x++) *dest++ = *src--; break; case gr90: src = buf->Row(buf->Height()-1) + y; for(int x=0; x<target.mRect.w; x++) { *dest++ = *src; src -= buf->GetStride(); } break; } } buf->DecRef(); } tile.mSurface->EndRender(); outAdvance = glyph.advance; return tile; } outAdvance = glyph.advance; return mSheets[glyph.sheet]->GetTile(glyph.tile); }