Dirty::Dirty(Image* image, Image* image_diff) : m_imgtype(image->imgtype) , m_x1(0), m_y1(0) , m_x2(image->w-1), m_y2(image->h-1) { int x, y, x1, x2; for (y=0; y<image->h; y++) { x1 = -1; for (x=0; x<image->w; x++) { if (image_getpixel(image, x, y) != image_getpixel(image_diff, x, y)) { x1 = x; break; } } if (x1 < 0) continue; for (x2=image->w-1; x2>x1; x2--) { if (image_getpixel(image, x2, y) != image_getpixel(image_diff, x2, y)) break; } Col* col = new Col(x1, x2-x1+1); col->data.resize(getLineSize(col->w)); Row* row = new Row(y); row->cols.push_back(col); m_rows.push_back(row); } }
// static Color Color::fromImageGetPixel(Image *image, int x, int y) { if ((x >= 0) && (y >= 0) && (x < image->w) && (y < image->h)) return Color::fromImage(image->getPixelFormat(), image_getpixel(image, x, y)); else return Color::fromMask(); }
static void ase_file_write_mask_chunk(FILE *f, Mask *mask) { int c, u, v, byte; const gfx::Rect& bounds(mask->getBounds()); ase_file_write_start_chunk(f, ASE_FILE_CHUNK_MASK); fputw(bounds.x, f); fputw(bounds.y, f); fputw(bounds.w, f); fputw(bounds.h, f); ase_file_write_padding(f, 8); // Name ase_file_write_string(f, mask->getName().c_str()); // Bitmap for (v=0; v<bounds.h; v++) for (u=0; u<(bounds.w+7)/8; u++) { byte = 0; for (c=0; c<8; c++) if (image_getpixel(mask->getBitmap(), u*8+c, v)) byte |= (1<<(7-c)); fputc(byte, f); } ase_file_write_close_chunk(f); }
int Sprite::getPixel(int x, int y, FrameNumber frame) const { int color = 0; if ((x >= 0) && (y >= 0) && (x < m_width) && (y < m_height)) { Image* image = Image::create(m_format, 1, 1); image_clear(image, (m_format == IMAGE_INDEXED ? getTransparentColor(): 0)); render(image, -x, -y, frame); color = image_getpixel(image, 0, 0); image_free(image); } return color; }
void image_putpen(Image* image, Pen* pen, int x, int y, int fg_color, int bg_color) { Image* pen_image = pen->get_image(); int u, v, size = pen->get_size(); x -= size/2; y -= size/2; if (fg_color == bg_color) { image_rectfill(image, x, y, x+pen_image->w-1, y+pen_image->h-1, bg_color); } else { for (v=0; v<pen_image->h; v++) { for (u=0; u<pen_image->w; u++) { if (image_getpixel(pen_image, u, v)) image_putpixel(image, x+u, y+v, fg_color); else image_putpixel(image, x+u, y+v, bg_color); } } } }
void UndoTransaction::autocropSprite(int bgcolor) { int old_frame = m_sprite->getCurrentFrame(); int x1, y1, x2, y2; int u1, v1, u2, v2; x1 = y1 = INT_MAX; x2 = y2 = INT_MIN; Image* image = Image::create(m_sprite->getPixelFormat(), m_sprite->getWidth(), m_sprite->getHeight()); for (int frame=0; frame<m_sprite->getTotalFrames(); ++frame) { m_sprite->setCurrentFrame(frame); m_sprite->render(image, 0, 0); // TODO configurable (what color pixel to use as "refpixel", // here we are using the top-left pixel by default) if (image_shrink_rect(image, &u1, &v1, &u2, &v2, image_getpixel(image, 0, 0))) { x1 = MIN(x1, u1); y1 = MIN(y1, v1); x2 = MAX(x2, u2); y2 = MAX(y2, v2); } } m_sprite->setCurrentFrame(old_frame); image_free(image); // do nothing if (x1 > x2 || y1 > y2) return; cropSprite(gfx::Rect(x1, y1, x2-x1+1, y2-y1+1), bgcolor); }
void DocumentApi::trimSprite(Sprite* sprite, int bgcolor) { gfx::Rect bounds; UniquePtr<Image> image_wrap(Image::create(sprite->getPixelFormat(), sprite->getWidth(), sprite->getHeight())); Image* image = image_wrap.get(); for (FrameNumber frame(0); frame<sprite->getTotalFrames(); ++frame) { image->clear(0); sprite->render(image, 0, 0, frame); // TODO configurable (what color pixel to use as "refpixel", // here we are using the top-left pixel by default) gfx::Rect frameBounds; if (image_shrink_rect(image, frameBounds, image_getpixel(image, 0, 0))) bounds = bounds.createUnion(frameBounds); } if (!bounds.isEmpty()) cropSprite(sprite, bounds, bgcolor); }
/* flooder: * Fills a horizontal line around the specified position, and adds it * to the list of drawn segments. Returns the first x coordinate after * the part of the line which it has dealt with. */ static int flooder (Image *image, int x, int y, int src_color, int tolerance, void *data, AlgoHLine proc) { FLOODED_LINE *p; int left = 0, right = 0; int c; switch (image->getPixelFormat()) { case IMAGE_RGB: { uint32_t* address = ((uint32_t**)image->line)[y]; /* check start pixel */ if (!color_equal_32((int)*(address+x), src_color, tolerance)) return x+1; /* work left from starting point */ for (left=x-1; left>=0; left--) { if (!color_equal_32((int)*(address+left), src_color, tolerance)) break; } /* work right from starting point */ for (right=x+1; right<image->w; right++) { if (!color_equal_32((int)*(address+right), src_color, tolerance)) break; } } break; case IMAGE_GRAYSCALE: { uint16_t* address = ((uint16_t**)image->line)[y]; /* check start pixel */ if (!color_equal_16((int)*(address+x), src_color, tolerance)) return x+1; /* work left from starting point */ for (left=x-1; left>=0; left--) { if (!color_equal_16((int)*(address+left), src_color, tolerance)) break; } /* work right from starting point */ for (right=x+1; right<image->w; right++) { if (!color_equal_16((int)*(address+right), src_color, tolerance)) break; } } break; case IMAGE_INDEXED: { uint8_t* address = ((uint8_t**)image->line)[y]; /* check start pixel */ if (!color_equal_8((int)*(address+x), src_color, tolerance)) return x+1; /* work left from starting point */ for (left=x-1; left>=0; left--) { if (!color_equal_8((int)*(address+left), src_color, tolerance)) break; } /* work right from starting point */ for (right=x+1; right<image->w; right++) { if (!color_equal_8((int)*(address+right), src_color, tolerance)) break; } } break; default: /* check start pixel */ if (image_getpixel(image, x, y) != src_color) return x+1; /* work left from starting point */ for (left=x-1; left>=0; left--) { if (image_getpixel(image, left, y) != src_color) break; } /* work right from starting point */ for (right=x+1; right<image->w; right++) { if (image_getpixel(image, right, y) != src_color) break; } break; } left++; right--; /* draw the line */ (*proc)(left, y, right, data); /* store it in the list of flooded segments */ c = y; p = FLOOD_LINE(c); if (p->flags) { while (p->next) { c = p->next; p = FLOOD_LINE(c); } p->next = c = flood_count++; _grow_scratch_mem(sizeof(FLOODED_LINE) * flood_count); p = FLOOD_LINE(c); } p->flags = FLOOD_IN_USE; p->lpos = left; p->rpos = right; p->y = y; p->next = 0; if (y > 0) p->flags |= FLOOD_TODO_ABOVE; if (y+1 < image->h) p->flags |= FLOOD_TODO_BELOW; return right+2; }
/* floodfill: * Fills an enclosed area (starting at point x, y) with the specified color. */ void algo_floodfill(Image* image, int x, int y, int tolerance, void *data, AlgoHLine proc) { int src_color; int c, done; FLOODED_LINE *p; /* make sure we have a valid starting point */ if ((x < 0) || (x >= image->w) || (y < 0) || (y >= image->h)) return; /* what color to replace? */ src_color = image_getpixel (image, x, y); /* set up the list of flooded segments */ _grow_scratch_mem(sizeof(FLOODED_LINE) * image->h); flood_count = image->h; p = (FLOODED_LINE*)_scratch_mem; for (c=0; c<flood_count; c++) { p[c].flags = 0; p[c].lpos = SHRT_MAX; p[c].rpos = SHRT_MIN; p[c].y = y; p[c].next = 0; } /* start up the flood algorithm */ flooder(image, x, y, src_color, tolerance, data, proc); /* continue as long as there are some segments still to test */ do { done = true; /* for each line on the screen */ for (c=0; c<flood_count; c++) { p = FLOOD_LINE(c); /* check below the segment? */ if (p->flags & FLOOD_TODO_BELOW) { p->flags &= ~FLOOD_TODO_BELOW; if (check_flood_line(image, p->y+1, p->lpos, p->rpos, src_color, tolerance, data, proc)) { done = false; p = FLOOD_LINE(c); } } /* check above the segment? */ if (p->flags & FLOOD_TODO_ABOVE) { p->flags &= ~FLOOD_TODO_ABOVE; if (check_flood_line(image, p->y-1, p->lpos, p->rpos, src_color, tolerance, data, proc)) { done = false; /* special case shortcut for going backwards */ if ((c < image->h) && (c > 0)) c -= 2; } } } } while (!done); }
static void thumbnail_render(BITMAP* bmp, const Image* image, bool has_alpha, const Palette* palette) { register int c, x, y; int w, h, x1, y1; double sx, sy, scale; ASSERT(image != NULL); sx = (double)image->w / (double)bmp->w; sy = (double)image->h / (double)bmp->h; scale = MAX(sx, sy); w = image->w / scale; h = image->h / scale; w = MIN(bmp->w, w); h = MIN(bmp->h, h); x1 = bmp->w/2 - w/2; y1 = bmp->h/2 - h/2; x1 = MAX(0, x1); y1 = MAX(0, y1); /* with alpha blending */ if (has_alpha) { register int c2; rectgrid(bmp, 0, 0, bmp->w-1, bmp->h-1, bmp->w/4, bmp->h/4); switch (image->getPixelFormat()) { case IMAGE_RGB: for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); c2 = getpixel(bmp, x1+x, y1+y); c = _rgba_blend_normal(_rgba(getr(c2), getg(c2), getb(c2), 255), c, 255); putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c))); } break; case IMAGE_GRAYSCALE: for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); c2 = getpixel(bmp, x1+x, y1+y); c = _graya_blend_normal(_graya(getr(c2), 255), c, 255); putpixel(bmp, x1+x, y1+y, makecol(_graya_getv(c), _graya_getv(c), _graya_getv(c))); } break; case IMAGE_INDEXED: { for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); if (c != 0) { ASSERT(c >= 0 && c < palette->size()); c = palette->getEntry(MID(0, c, palette->size()-1)); putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c))); } } break; } } } /* without alpha blending */ else { clear_to_color(bmp, makecol(128, 128, 128)); switch (image->getPixelFormat()) { case IMAGE_RGB: for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c))); } break; case IMAGE_GRAYSCALE: for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); putpixel(bmp, x1+x, y1+y, makecol(_graya_getv(c), _graya_getv(c), _graya_getv(c))); } break; case IMAGE_INDEXED: { for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); ASSERT(c >= 0 && c < palette->size()); c = palette->getEntry(MID(0, c, palette->size()-1)); putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c))); } break; } } } }