{"id":887,"date":"2023-06-20T23:13:50","date_gmt":"2023-06-20T21:13:50","guid":{"rendered":"https:\/\/betalord.com\/code\/?p=887"},"modified":"2023-06-20T23:17:44","modified_gmt":"2023-06-20T21:17:44","slug":"process-9-patch-image-file-manually","status":"publish","type":"post","link":"https:\/\/betalord.com\/code\/2023\/06\/20\/process-9-patch-image-file-manually\/","title":{"rendered":"Process 9-patch image file manually"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"887\" class=\"elementor elementor-887\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-badf58b elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"badf58b\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-6259911\" data-id=\"6259911\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-c3635a1 elementor-widget elementor-widget-text-editor\" data-id=\"c3635a1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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&#8217;t provide any tool to do that manually (only via atlases), I had to write the code myself.\u00a0 Hopefully it will help someone else too:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-b0c9b3b elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"b0c9b3b\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-fbec031\" data-id=\"fbec031\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-15fefa2 elementor-widget elementor-widget-code-block-for-elementor\" data-id=\"15fefa2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-block-for-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre class='line-numbers theme-okaidia' data-show-toolbar='yes'><code class='language-java'>\t\/**\r\n\t * This method loads 9-patch from given file and creates a NinePatch object out of it.\r\n\t * &lt;p&gt;\r\n\t * Note that a new Texture is generated by this method that needs to be manually disposed of when\r\n\t * the returning NinePatch is no longer needed (by doing &quot;NinePatch.getTexture().dispose()&quot;).\r\n\t * &lt;p&gt;\r\n\t * libGDX&#039;s code that processes 9-patch markers is located in {@link ImageProcessor} class\r\n\t * (the code here is not based on the libGDX&#039;s code though).\r\n\t *\r\n\t * @param ninePatchFile file handle of a 9-patch file (it normally ends in &quot;.9.png&quot;).\r\n\t * @return NinePatch object created from 9-patch image file\r\n\t * @author Betalord\r\n\t *\/\r\n\tpublic static NinePatch readNinePatch(FileHandle ninePatchFile) {\r\n\t\t\/\/ NOTE: point (0,0) is in left-top corner of a texture.\r\n\t\t\r\n\t\tfinal int black = Color.rgba8888(Color.BLACK);\r\n\t\t\r\n\t\tPixmap pm = new Pixmap(ninePatchFile);\r\n\t\tPixmap pmTex = new Pixmap(pm.getWidth()-2, pm.getHeight()-2, pm.getFormat()); \/\/ cut out the black markers of nine-patch\r\n\t\tpmTex.drawPixmap(pm, 0, 0, 1, 1, pm.getWidth()-2, pm.getHeight()-2);\r\n\t\t\r\n\t\tTexture t = new Texture(pmTex);\r\n\t\t\r\n\t\t\/\/ process it:\r\n\t\t\r\n\t\t\/\/ let&#039;s detect scalable area:\r\n\t\t\r\n\t\tint left = -1; \/\/ the left-most black pixel\r\n\t\tint right = -1; \/\/ the right-most black pixel\r\n\t\tint top = -1; \/\/ the top-most black pixel\r\n\t\tint bottom = -1; \/\/ the bottom-most black pixel\r\n\t\t\r\n\t\tboolean last = false; \/\/ was last pixel black?\r\n\t\tfor (int i = 0; i &lt; pm.getWidth(); i++) {\r\n\t\t\tint p = pm.getPixel(i, 0);\r\n\t\t\t\r\n\t\t\tif (!last &amp;&amp; p == black) left = i;\r\n\t\t\t\r\n\t\t\tif (last &amp;&amp; p != black) {\r\n\t\t\t\tright = i-1;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (p == black)\r\n\t\t\t\tlast = true;\r\n\t\t}\r\n\t\t\r\n\t\tlast = false; \/\/ was last pixel black?\r\n\t\tfor (int i = 0; i &lt; pm.getHeight(); i++) {\r\n\t\t\tint p = pm.getPixel(0, i);\r\n\t\t\t\r\n\t\t\tif (!last &amp;&amp; p == black) top = i;\r\n\t\t\t\r\n\t\t\tif (last &amp;&amp; p != black) {\r\n\t\t\t\tbottom = i-1;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (p == black)\r\n\t\t\t\tlast = true;\r\n\t\t}\r\n\t\t\r\n\t\t\/\/ now let&#039;s detect padding (fill area):\r\n\t\t\r\n\t\tint pad_left = -1, pad_right = -1, pad_top = -1, pad_bottom = -1;\r\n\t\t\r\n\t\tlast = false; \/\/ was last pixel black?\r\n\t\tfor (int i = 0; i &lt; pm.getWidth(); i++) {\r\n\t\t\tint p = pm.getPixel(i, pm.getHeight()-1);\r\n\t\t\t\r\n\t\t\tif (!last &amp;&amp; p == black) pad_left = i;\r\n\t\t\t\r\n\t\t\tif (last &amp;&amp; p != black) {\r\n\t\t\t\tpad_right = i-1;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (p == black)\r\n\t\t\t\tlast = true;\r\n\t\t}\r\n\t\t\r\n\t\tlast = false; \/\/ was last pixel black?\r\n\t\tfor (int i = 0; i &lt; pm.getHeight(); i++) {\r\n\t\t\tint p = pm.getPixel(pm.getWidth()-1, i);\r\n\t\t\t\r\n\t\t\tif (!last &amp;&amp; p == black) pad_top = i;\r\n\t\t\t\r\n\t\t\tif (last &amp;&amp; p != black) {\r\n\t\t\t\tpad_bottom = i-1;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (p == black)\r\n\t\t\t\tlast = true;\r\n\t\t}\r\n\t\t\r\n\t\t\/\/ construct a 9-patch:\r\n\t\tTextureRegion\r\n\t\t\t\ttl, ml, bl, \/\/ top-left, middle-left, bottom-left\r\n\t\t\t\ttm, mm, bm, \/\/ top-middle, middle-middle, bottom-middle\r\n\t\t\t\ttr, mr, br; \/\/ top-right, middle-right, bottom-right\r\n\t\t\r\n\t\t\/*\r\n\t\t * Order of processing:\r\n\t\t * #####\r\n\t\t * #147#\r\n\t\t * #258#\r\n\t\t * #369#\r\n\t\t * #####\r\n\t\t *\/\r\n\t\t\r\n\t\t\/\/ TextureRegion constructor args: x, y, width, height\r\n\t\t\r\n\t\t\/\/ adjust markers to match &quot;inner&quot; texture&#039;s dimensions (which is missing 9-match black marker borders):\r\n\t\tleft--;\r\n\t\tright--;\r\n\t\ttop--;\r\n\t\tbottom--;\r\n\t\tpad_left--;\r\n\t\tpad_right--;\r\n\t\tpad_top--;\r\n\t\tpad_bottom--;\r\n\t\t\r\n\t\ttl = new TextureRegion(t, 0, 0, left, top);\r\n\t\tml = new TextureRegion(t, 0, top, left, bottom-top+1);\r\n\t\tbl = new TextureRegion(t, 0, bottom+1, left, t.getHeight()-bottom-1);\r\n\t\t\r\n\t\ttm = new TextureRegion(t, left, 0, right-left+1, top);\r\n\t\tmm = new TextureRegion(t, left, top, right-left+1, bottom-top+1);\r\n\t\tbm = new TextureRegion(t, left, bottom+1, right-left+1, t.getHeight()-bottom-1);\r\n\t\t\r\n\t\ttr = new TextureRegion(t, right+1, 0, t.getWidth()-right-1, top);\r\n\t\tmr = new TextureRegion(t, right+1, top, t.getWidth()-right-1, bottom-top+1);\r\n\t\tbr = new TextureRegion(t, right+1, bottom+1, t.getWidth()-right-1, t.getHeight()-bottom-1);\r\n\t\t\r\n\t\tNinePatch n = new NinePatch(tl, tm, tr, ml, mm, mr, bl, bm, br);\r\n\t\t\/\/ set the padding:\r\n\t\tn.setPadding(pad_left, t.getWidth()-pad_right-1, pad_top, t.getHeight()-pad_bottom-1); \/\/ this code hasn&#039;t really been tested yet (should work though)!\r\n\t\t\r\n\t\t\/\/ clean up the memory (except for the texture itself which should be disposed by the called):\r\n\t\tpm.dispose();\r\n\t\tpmTex.dispose();\r\n\t\t\r\n\t\treturn n;\r\n\t}<\/code><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Recently I had to load .9.png file manually (a nine-patch) and create a NinePatch object out of it in libGDX. Since libGDX [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17],"tags":[12,10],"class_list":["post-887","post","type-post","status-publish","format-standard","hentry","category-article","tag-java","tag-libgdx"],"_links":{"self":[{"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/posts\/887","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/comments?post=887"}],"version-history":[{"count":4,"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/posts\/887\/revisions"}],"predecessor-version":[{"id":891,"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/posts\/887\/revisions\/891"}],"wp:attachment":[{"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/media?parent=887"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/categories?post=887"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/betalord.com\/code\/wp-json\/wp\/v2\/tags?post=887"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}