Process 9-patch image file manually

Recently I had to load .9.png file manually (a nine-patch) and create a NinePatch object out of it in libGDX. Since libGDX doesn’t provide any tool to do that manually (only via atlases), I had to write the code myself.  Hopefully it will help someone else too:

	/**
	 * This method loads 9-patch from given file and creates a NinePatch object out of it.
	 * <p>
	 * Note that a new Texture is generated by this method that needs to be manually disposed of when
	 * the returning NinePatch is no longer needed (by doing "NinePatch.getTexture().dispose()").
	 * <p>
	 * libGDX's code that processes 9-patch markers is located in {@link ImageProcessor} class
	 * (the code here is not based on the libGDX's code though).
	 *
	 * @param ninePatchFile file handle of a 9-patch file (it normally ends in ".9.png").
	 * @return NinePatch object created from 9-patch image file
	 * @author Betalord
	 */
	public static NinePatch readNinePatch(FileHandle ninePatchFile) {
		// NOTE: point (0,0) is in left-top corner of a texture.
		
		final int black = Color.rgba8888(Color.BLACK);
		
		Pixmap pm = new Pixmap(ninePatchFile);
		Pixmap pmTex = new Pixmap(pm.getWidth()-2, pm.getHeight()-2, pm.getFormat()); // cut out the black markers of nine-patch
		pmTex.drawPixmap(pm, 0, 0, 1, 1, pm.getWidth()-2, pm.getHeight()-2);
		
		Texture t = new Texture(pmTex);
		
		// process it:
		
		// let's detect scalable area:
		
		int left = -1; // the left-most black pixel
		int right = -1; // the right-most black pixel
		int top = -1; // the top-most black pixel
		int bottom = -1; // the bottom-most black pixel
		
		boolean last = false; // was last pixel black?
		for (int i = 0; i < pm.getWidth(); i++) {
			int p = pm.getPixel(i, 0);
			
			if (!last && p == black) left = i;
			
			if (last && p != black) {
				right = i-1;
				break;
			}
			
			if (p == black)
				last = true;
		}
		
		last = false; // was last pixel black?
		for (int i = 0; i < pm.getHeight(); i++) {
			int p = pm.getPixel(0, i);
			
			if (!last && p == black) top = i;
			
			if (last && p != black) {
				bottom = i-1;
				break;
			}
			
			if (p == black)
				last = true;
		}
		
		// now let's detect padding (fill area):
		
		int pad_left = -1, pad_right = -1, pad_top = -1, pad_bottom = -1;
		
		last = false; // was last pixel black?
		for (int i = 0; i < pm.getWidth(); i++) {
			int p = pm.getPixel(i, pm.getHeight()-1);
			
			if (!last && p == black) pad_left = i;
			
			if (last && p != black) {
				pad_right = i-1;
				break;
			}
			
			if (p == black)
				last = true;
		}
		
		last = false; // was last pixel black?
		for (int i = 0; i < pm.getHeight(); i++) {
			int p = pm.getPixel(pm.getWidth()-1, i);
			
			if (!last && p == black) pad_top = i;
			
			if (last && p != black) {
				pad_bottom = i-1;
				break;
			}
			
			if (p == black)
				last = true;
		}
		
		// construct a 9-patch:
		TextureRegion
				tl, ml, bl, // top-left, middle-left, bottom-left
				tm, mm, bm, // top-middle, middle-middle, bottom-middle
				tr, mr, br; // top-right, middle-right, bottom-right
		
		/*
		 * Order of processing:
		 * #####
		 * #147#
		 * #258#
		 * #369#
		 * #####
		 */
		
		// TextureRegion constructor args: x, y, width, height
		
		// adjust markers to match "inner" texture's dimensions (which is missing 9-match black marker borders):
		left--;
		right--;
		top--;
		bottom--;
		pad_left--;
		pad_right--;
		pad_top--;
		pad_bottom--;
		
		tl = new TextureRegion(t, 0, 0, left, top);
		ml = new TextureRegion(t, 0, top, left, bottom-top+1);
		bl = new TextureRegion(t, 0, bottom+1, left, t.getHeight()-bottom-1);
		
		tm = new TextureRegion(t, left, 0, right-left+1, top);
		mm = new TextureRegion(t, left, top, right-left+1, bottom-top+1);
		bm = new TextureRegion(t, left, bottom+1, right-left+1, t.getHeight()-bottom-1);
		
		tr = new TextureRegion(t, right+1, 0, t.getWidth()-right-1, top);
		mr = new TextureRegion(t, right+1, top, t.getWidth()-right-1, bottom-top+1);
		br = new TextureRegion(t, right+1, bottom+1, t.getWidth()-right-1, t.getHeight()-bottom-1);
		
		NinePatch n = new NinePatch(tl, tm, tr, ml, mm, mr, bl, bm, br);
		// set the padding:
		n.setPadding(pad_left, t.getWidth()-pad_right-1, pad_top, t.getHeight()-pad_bottom-1); // this code hasn't really been tested yet (should work though)!
		
		// clean up the memory (except for the texture itself which should be disposed by the called):
		pm.dispose();
		pmTex.dispose();
		
		return n;
	}