Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- fun unpack(spriteSheet: Path): List<Image> {
- Preconditions.checkArgument(Files.exists(spriteSheet),
- "The file ${spriteSheet.getFileName()} does not exist")
- logger.debug("Loading sprite sheet.")
- // TODO: Convert to png so we have an alpha layer to work with
- val spriteSheetImage = readImage(spriteSheet).toBufferedImage()
- logger.debug("Determining most probable background color.")
- val backgroundColor = determineProbableBackgroundColor(spriteSheetImage)
- logger.debug("The most probable background color is $backgroundColor")
- return findSprites(spriteSheetImage, backgroundColor) map(::copySubImage.bindFirst(spriteSheetImage))
- }
- private fun findSprites(image: BufferedImage,
- backgroundColor: Color): List<Rectangle> {
- val workingImage = copy(image)
- val spriteRectangles = ArrayList<Rectangle>()
- for (pixel in workingImage) {
- val (point, color) = pixel
- if (color != backgroundColor) {
- logger.debug("Found a sprite starting at (${point.x}, ${point.y})")
- val spritePlot = findContiguous(workingImage, point) { it != backgroundColor }
- val spriteRectangle = Rectangle(spritePlot, image)
- logger.debug("The identified sprite has an area of ${spriteRectangle.width}x${spriteRectangle.height}")
- spriteRectangles.add(spriteRectangle)
- eraseSprite(workingImage, backgroundColor, spritePlot)
- }
- }
- logger.info("Found ${spriteRectangles.size()} sprites.")
- return spriteRectangles
- }
- private fun findContiguous(image: BufferedImage, point: Point, predicate: (Color) -> Boolean): List<Point> {
- val unvisited = LinkedList<Point>()
- val visited = HashSet<Point>()
- unvisited.addAll(neighbors(point, image) filter { predicate(Color(image.getRGB(it.x, it.y))) })
- while (unvisited.isNotEmpty()) {
- val currentPoint = unvisited.pop()
- val currentColor = Color(image.getRGB(currentPoint.x, currentPoint.y))
- if (predicate(currentColor)) {
- unvisited.addAll(neighbors(currentPoint, image) filter {
- !visited.contains(it) && !unvisited.contains(it) &&
- predicate(Color(image.getRGB(it.x, it.y)))
- })
- visited.add(currentPoint)
- }
- }
- return visited.toList()
- }
- private fun neighbors(point: Point, image: Image): List<Point> {
- val points = ArrayList<Point>()
- if (point.x > 0)
- points.add(Point(point.x - 1, point.y))
- if (point.x < image.getWidth(null) - 1)
- points.add(Point(point.x + 1, point.y))
- if (point.y > 0)
- points.add(Point(point.x, point.y - 1))
- if (point.y < image.getHeight(null) - 1)
- points.add(Point(point.x, point.y + 1))
- return points
- }
- Public Function IntersectsWith(rectb As strRect, expand As Integer) As Boolean
- If isEmpty Or rectb.isEmpty Then Return False
- If Not (m_top - expand <= rectb.m_bottom + expand) Then Return False
- If Not (m_bottom + expand >= rectb.m_top - expand) Then Return False
- If Not (m_left - expand <= rectb.m_right + expand) Then Return False
- If Not (m_right + expand >= rectb.m_left - expand) Then Return False
- Return True
- End Function
- m_bmp = DirectCast(p_bmp.Clone(), Bitmap)
- Dim lock As BitmapData = BMPLock(m_bmp)
- Dim dword_bgcolor As Integer = bgcolor.ToArgb
- ' first smash the copied bitmap into either BG or non bg so can search exact
- For i As Integer = 0 To lock.Width * lock.Height - 1
- If BMPColorsAreSimilar(BMPGetPixelFastDWORD(lock, i), dword_bgcolor, tol) > 0 Then ' bg
- BMPSetPixelFast(lock, i, 0)
- Else
- BMPSetPixelFast(lock, i, 1)
- End If
- Next
- Dim rect As strRect
- Dim temp_stack As New Stack ' fill algo uses this... passing it means not allocated every call
- For y As Integer = 0 To lock.Height - 1
- For x As Integer = 0 To lock.Width - 1
- If BMPGetPixelFastDWORD(lock, x, y) = 1 Then ' hit a sprite so erase it with flood fill to get the bounds
- BMPFloodFill(lock, temp_stack, filldiag, x, y, 0)
- rect.SetBounds(BMPFloodFillLastMinX(), BMPFloodFillLastMaxX(), BMPFloodFillLastMinY, BMPFloodFillLastMaxY)
- m_bounds.Add(rect) ' add to our list of rectangles
- End If
- Next
- Next
- int fill_dx[] = { 0, -1, 0, 1, -1, -1, 1, 1 };
- int fill_dy[] = { -1, 0, 1, 0, -1, 1, -1, 1 };
- int fill_minx;
- int fill_miny;
- int fill_maxx;
- int fill_maxy;
- BYTE *fill_track = 0;
- DWORD fill_track_size = 0;
- Int32 MCUMakerSupport::MCUBitmap::BMPFloodFill(BitmapData ^%bmp_lock, Stack ^%mCods, Int32 diag, Int32 x, Int32 y, Int32 col)
- {
- diag = diag ? 8 : 4;
- if (!bmp_lock)
- {
- return 0;
- }
- int w = bmp_lock->Width;
- int h = bmp_lock->Height;
- if (x < 0 || x >= w || y < 0 || y >= h) return 0;
- refill:
- if (!fill_track)
- {
- fill_track = (BYTE *)malloc(w * h);
- fill_track_size = w * h;
- }
- else
- {
- if (fill_track_size < w * h)
- {
- free(fill_track);
- fill_track = 0;
- fill_track_size = 0;
- goto refill;
- }
- }
- if (!fill_track)
- {
- fill_track_size = 0;
- return 0;
- }
- memset(fill_track, 0, w * h);
- //BitmapData ^bmp_lock = bmp->LockBits(Rectangle(0, 0, w, h), ImageLockMode::ReadWrite, bmp->PixelFormat);
- DWORD *fill_addr = (DWORD *)bmp_lock->Scan0.ToPointer();
- DWORD fill_color = col;
- DWORD target_color = fill_addr[y * w + x];
- //Stack ^mCods = gcnew Stack();
- Point pt;
- pt.X = x;
- pt.Y = y;
- mCods->Clear();
- int filled = 1;
- fill_minx = fill_maxx = x;
- fill_miny = fill_maxy = y;
- fill_addr[pt.Y * w + pt.X] = fill_color;
- fill_track[pt.Y * w + pt.X] = 255;
- mCods->Push(pt);
- while (mCods->Count > 0)
- {
- recheck:
- for (int i = 0; i < diag; i++)
- {
- int cx = pt.X + fill_dx[i];
- if (cx < 0 || cx >= w) continue;
- int cy = pt.Y + fill_dy[i];
- if (cy < 0 || cy >= h) continue;
- bool res = false;
- if (!fill_track[cy * w + cx])
- {
- fill_track[cy * w + cx]++;
- DWORD c = fill_addr[cy * w + cx];
- if (c == target_color)
- {
- res = true;
- fill_addr[cx + cy * w] = fill_color;
- if (cx < fill_minx) { fill_minx = cx; }
- if (cy < fill_miny) { fill_miny = cy; }
- if (cx > fill_maxx) { fill_maxx = cx; }
- if (cy > fill_maxy) { fill_maxy = cy; }
- }
- }
- if (res) // fill?
- {
- mCods->Push(pt);
- filled++;
- pt.Y = cy;
- pt.X = cx;
- goto recheck;
- }
- }
- pt.X = ((Point ^)mCods->Peek())->X;
- pt.Y = ((Point ^)mCods->Peek())->Y;
- mCods->Pop();
- }
- mCods->Clear();
- return filled; // number of pixels filled
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement