Hi, Im using Xors3D and I use Writepixel and readpixel commands.
the writepixel is much slower than readpixel.. in xors3d
is it the same in blitzmax read write pixel?
also is there anything that can be done to make it faster?
Cheers
I guess no one has a clue
ReadPixel and WritePixel commands themselves are actually quite fast. The problem comes when you need to display the imgae. The image is modified in the CPU's memory, so must be transfered over the bus to the GPU's memory before it can be displayed. This actually takes time. That is why it takes so much longer to write to an image than read from it.
But when im writing pixel i dont display it..
so i dont understand why its slow
How many pixels are you writing?
A full screen or a handful?
How many functions, calculations are you doing per pixel?
Are you performing any slow operations per pixel such as square roots or trig functions?
Are you calculating rgb values with a function call or a calculation?
I do no function calculation on the pixel i just read a pixel from one image and and write on another and it can start from 1000 and get to million approx..
Well if there are no calculations or processing why not use a copyrect method instead of pixel writing and reading?
because i need to read pixel by pixel for what im doing.. :)
but thanks for the suggestion :) here is what im working on https://1drv.ms/u/s!ArSvOuhm7L3ko51b1gpP7GPIeBy8bw?e=HXdnj7
Okay. Here is another suggestion.
Do all your readpixels in one set.
Then all the writepixels.
In otherwords dont alternate between reading 1 pixel then writing 1 pixel.
Do them all at once.
Also if you can do multithreading then read each channel r g b and a in a thread each and process each colour channel on a separate thread.
very interesting idea! ill give it a try! thanks
i have no clue about multi threading.. never dealed with it
Have a data portion to work on ... and use a Mutex to protect write accesses to it. Unlock the mutex everytime you are done.
For "numbers" this is not problematic as you can simple have threads eg do
pixels 0-99
pixels 100-199
pixels 200-299
...
So none of these groups overlap. They do not change memory addresses - but straight content of "numbers" in the number array (a pixmap is a row of integers containing RGB(A)).
So perfect for threaded processing.
Yet it is better to describe what you actually are doing - as a pixmap of 2k*2k is not that "slow" to compute each frame, but if you compute a 8k*8k 20 times a frame, then you might run into trouble.
Another idea is to make it "async" - so give it to a thread to process and use the old one until the thread is done (so it might be there in the same frame - or 1000 seconds later).
bye
Ron
Unfortunately your link is asking me for a password for some reason. But is it possible to do what you want using shaders? This will allow you to process your images directly on the GPU, which means fast.
I clicked on the link and it downloaded a PNGSplitter.rar (automatically) and it was able to unpack it.
According to the name he wants to read parts from a pixmap and create a new pixmap out of it. But maybe it is for some live preview or so.
Would be good to know in "abstract" what Hardcoal wants to do exactly.
bye
Ron
Ill fix the link soon
What im doing is taking a tile set single png and turning it into separate pngs
Yes - and this should be "blazing fast" - exception is if you need to find the sprites on your own (eg minimum island size) and then do auto-crop etc.
But this is not strictly readpixel/writepixel slowness then but also the algorithm you use.
So ... assume we have 10 sprites on an image - and you know the coords + dimension of each. Extracting this data into new PNGs, is this then slow for you? I doubt it.
As said _read_ access to TPixmap can be multithreaded without much hassle.
Next to classic "threading" you could use what @Brucey once wrote: some "Workers" (you then just pass your task "split images" to the workers and they spawn as much as required, and once done they spawn new ones if there are still images to strip from the image). Means you do not have a fixed amount of threads you send out to strip image slices but a flexible amount of runners utilizing threads - more on this if interested.
So the more you explain (without loosing yourself in too much implementation details) the more easily we could help and spot issues.
bye
Ron
Ill simply post the code
But again it's in xors
Thought you were using TPixmap (Max2D) ?
local img:TPixmap = LoadPixmap("your.png")
local otherImg:TPixmap = CreatePixmap(tileW, tileH, img.format)
otherImg.WritePixel(x,y, img.ReadPixel(x - offsetX, y - offsetY))
bye
Ron
ok here is part of my code.
Derron Hi.. I dont need it to be blazing fast just normally fast :)
i didnt read all replies well im on a hurry ill go through them later..
mean while here is part of my code..
also a new link to my demo https://drive.google.com/file/d/1kugyDoI-uF_XwkHDkiu_lE2yWnJkOvzU/view?usp=sharing
Method ReadPNG(ImageHandle, CurrentX = 0, CurrentY = 0, Pixel[,] Var)
Local X, Y, StartX, StartY, NewPixel[ximagewidth(imagehandle), ximageheight(imagehandle)]
Local LeftX, RightX, UpY, DownY
'Start
Local Coords:Coords_Class = New Coords_Class
Coords = GetFirstEmptyPoint(ImageHandle, Pixel)
If Coords.X = -1 Then Return 'End Of Trace
StartX = Coords.X
StartY = Coords.Y
LeftX = StartX
RightX = StartX
UpY = StartY
DownY = StartY
NewPixel[StartX, StartY] = OccupiedPix 'A Must
Pixel[StartX, StartY] = OccupiedPix 'Not Certain
Coords = Null
'Left To Right
For Y = StartY To xImageHeight(ImageHandle) - 1
For X = 0 To xImageWidth(ImageHandle) - 1
'Is UnChecked
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()
Next
Next
'Right To Left And Down To Up
For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1
For X = xImageWidth(ImageHandle) - 1 To 0 Step - 1
'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()
Next
Next
'Up To Down [All Seems To Work]
For X = 0 To xImageWidth(ImageHandle) - 1
For Y = 0 To xImageHeight(ImageHandle) - 1
'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()
Next
Next
'Down To Up
For X = 0 To xImageWidth(ImageHandle) - 1
For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1
'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()
Next
Next
'Write The Image
Local NewImage = Xcreateimage (RightX - LeftX, DownY - UpY)
For Y = UpY To DownY
For X = LeftX To RightX
If NewPixel[X, Y] = OccupiedPix Then
xWritePixel(X - LeftX, Y - UpY, xReadPixel(X, Y, xImageBuffer(ImageHandle)), xImageBuffer(NewImage))
End If
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()
Next
Next
Return NewImage
End Method
So ... you want to split tiles from a tilemap. What happens if you have "islands" in the tile?.
Eg. There is a "sky tile" which has some separate clouds.
How to handle this?
You can only automate this if then the tiles are in a "grid" layout - so you define tile width and other stuff (like grid spacing). If you have dynamically sized tiles then you cannot have "islands" (or they will end up becoming separate sprites).
Edit: also important - certain image editors (GIMP!) do not set RGB information when deleting stuff - they just set the alpha value to 0. So when exporting your tileset and then compare against a color like "0" (rgba(0,0,0,0)) this will ignore these "only made transparent" pixels. So better compare for the alpha value.
Edit2: http://www.spritecow.com/ (js sources available) might be interesting to check out. So the interesting part is this: https://github.com/jakearchibald/sprite-cow/blob/master/www/assets/script/SpriteCanvas.js
If your tilemaps are always in a grid layout it is just a matter of cutting out the tiles and then removing all rows/cols with all pixels' alpha values being 0 ("auto cropping").
Edit3: https://github.com/bmarwane/spriteSplitter/blob/master/app/js/loader.js this does it a bit more "verbose".
bye
Ron
My program does exactly what I desired it to do..
In some cases it may not be suitable for some people, but in 99% of the times It will be fine..
I still do not know what it should do - compared to what it actually does (there is a missing function in your sample too).
This is why I asked for an abstract of what it should do - not an implementation of what you do.
bye
Ron
Sorry Derron.. I was so busy today in so many things.. i didnt have time to really look through the posts.. into details..
Ive added a Tileset in the folder of the Program like this one.. (https://i.imgur.com/Z5UexG8.png)
Press LoadTileSet Button and choose this png.. than press ConverToPNGS
After a while it will turn from a single Image to a multiple PNG Images.
It was made for my Editor use at first..
So I wont need to use photo shop to seperate tiles and save them one by one.
Yea its a work in progress..
so I dont blame you if youre confused..
Anyway.. its all going fine for me besides the speed thing..
but ill fix it later.. for now all is ok..
I prefer to deal with progressing this , instead of messing with the speed issue atm.
im gonna open a new thread soon . only for this little software.. and add the latest Demo
Thanks Derron for your Care
That looks nice Hardcoal.
However, if I understand you want a program to extract the individual square tiles from that tileset, or any tileset.
Perhaps a faster way would be the following algorithm.
1. Get width and height of image.
2. Find first non transparent pixel in a column.
3. Find first non transparent pixel in a row.
4. Find shortest distance in rows and columns to next transparent pixel.
5. Combining knowledge from points 2 to 4 you have the size of each tile plus its initial offset.
6. Grab rectangles of size defined in 5 and spit them out.
7. If there is transparency issues with resulting image then store transparency in greyscale image and recombine later.
Ignore if I'm completely off base.
Matty its all working fine.. I just tried to make it faster lol thats all..
Ill put the latest version of my App Soon.
Exactly, hence I suggested a faster algorithm than reading and writing every individual pixel.
What happens if you replace that xors commands with some pure tpixmap commands? Maybe this is the speed culprit?
Bye
Ron
Quote from: Hardcoal on March 02, 2020, 22:07:47
Ive added a Tileset in the folder of the Program like this one.. (https://i.imgur.com/Z5UexG8.png)
Press LoadTileSet Button and choose this png.. than press ConverToPNGS
After a while it will turn from a single Image to a multiple PNG Images.
Challenge Accepted, and accomplished https://www.syntaxbomb.com/index.php/topic,7474.msg347040328.html#msg347040328 (https://www.syntaxbomb.com/index.php/topic,7474.msg347040328.html#msg347040328) :)
Uses Pixmaps and directly accesses the pixels instead of using Read/WritePixel for faster access. You can save the resulting tiles with SavePixmapPNG command if you want.
@TomToad
Nice job - I changed the "show" portion to quickly draw all sprites ... which exposes a flaw in the dark green tile at the bottom right (above the "plus") of the original (see following picture):
(https://i.imgur.com/tli0mzj.png)
result of your algo:
(https://i.imgur.com/QtBuWAK.png)
This is what I by the way was talking about ("island detection")
You _could_ somehow circumvent it by increasing the "lookup" range for blank lines ("end of tile"). So if you knew that all tiles are at least X pixels away from each other (padding?) then you could use this to keep these tiles intact. But I do not see a way to "automate" this in all situations. So eg. your algorithm could check distance betwen tiles - and after this quick scan uses the most used distance as "minimum distance" between tiles.
bye
Ron
Quote from: Derron on March 03, 2020, 12:59:21
@TomToad
Nice job - I changed the "show" portion to quickly draw all sprites ... which exposes a flaw in the dark green tile at the bottom right (above the "plus") of the original (see following picture):
Are you refering to the four corner square part? My version requires that all pixels be connected continuously. There are 0 alpha pixels between each corner, so each one is extracted into its own tile. I guess you could create a "reach" variable, defined how close a pixel needs to be to be part of the same tile, and search through a grid of pixels instead of just left/right/up/down.
I did not want to say your code is not working - it just seems to not be what Hardcoal is trying to achieve (at least not 100%).
So yes, I was talking about it - and also knew in advance why it fails and that your code does not try to cope with it.
This aside your code is very helpful and I am tempted to add it to my Dig framework (once we matured/optimized it even more :D - maybe one could add borders to sprites and the extractor then just skips the border)
bye
Ron
Ok, I just added a "reach" parameter to the code. Now it will extract the tiles correctly. :) :)
Here is my last version..
Im planning to add more PNG Tools..
Also Im about to make Also Option to Turn a non Transparent Tile Set that will turn it into a PNG.
Thats pretty easy to do now that main thing is done..
Im simply too busy lately to put a lot of coding effort.. so ill take my time..
but its definitely gonna be faster than my damn game editor.
I started this process because i needed that for my editor..
https://drive.google.com/file/d/158pkbR3xtRHDXpUgcWjJJXCTooK5x3x2/view?usp=sharing
Ive Started with Xors so im not about to move the normal blitzmax..
I dont have the powers..
if anyone improved that code that i posted ill be glad to have it :)
This is the last code..
Type TilesSpliter_Section
Field TitleuN_bt = alCreateGScrollArea(alDesktop, "", 0, 30, 300, 30, 0)
Field Title_bt = Alba.CreateButtonWithImage_al(alDesktop, AppURL + "Media\TileSetSplitter.png", -2, 27, 300, 30)
Field Roller_Area = alCreateGScrollArea(alDesktop, "", 300, 30, 480, 30, 0)
Field LoadTileSet_bt = alCreateGButton(Roller_Area, "LoadTileSet", -2, -3, 100, 30)
Field Convert_bt = alCreateGButton(Roller_Area, "ConvertToPNGS", 128, -3, 115, 30)
Field SelectEmptySpace_bt = alCreateGButton(Roller_Area, "SelectBackGroundPixel", 270, -3, 170, 30)
'Versions
'Field Version_roller = alCreateGScrollArea(alDesktop, "", 780, 30, 130, 30, 0)
Field LiteVersion_Logo = Alba.CreateButtonWithImage_al(alDesktop, "Media/LiteVersion.png", 780, 30, 100, 30, True)
Field FullVersion_Logo = Alba.CreateButtonWithImage_al(alDesktop, "Media/FullVersion.png", 780, 30, 100, 30, True)
Field ForceStop_bt = alCreateGButton(alDesktop, "ForceStop", xsize / 2 - 50, ysize / 2 - 50, 130, 30)
Field Original_Win = alCreateGScrollArea(alDesktop, "", 0, 60, 880, 410)
Field ImageButton
'Field OutPut_win = alCreateGScrollArea(alDesktop, "", 880, 60, 400, 560)
Field OutputURL:String = "Output\"
Field PNGTileSETURF:String
Field TilesetImageHandle
Field TempNegativeImageHandle
Field Pixel[,]
Field Images[]
Field NewImageName:String
Const UnChecked = 0
Const OccupiedPix = 1
'----------------'
Field CurrentSection = Section_Normal
Const Section_Normal = 0
Const Section_ChoosePixel = 1
Method New()
alHide(ForceStop_bt)
Alba.SetElementColorBack(Original_Win, Alba.Color_Gray1)
Alba.SetElementColorBack(TitleuN_bt, Alba.Color_Brown)
Alba.SetElementColorBack(ForceStop_bt, Alba.Color_red)
Alba.SetRemark(LoadTileSet_bt, "Load A Tileset Single PNG and Turn it to Seperate PNGS")
Alba.SetRemark(Convert_bt, "Convert The Loaded Image To Seperate PNG's")
'Version Logo
If DemoVersion_flg = False Then
alHide(LiteVersion_Logo)
Else
alHide(FullVersion_Logo)
End If
End Method
Method Play()
Select CurrentSection
Case Section_Normal
'Load PNG TileSet
If alTestClick(TS.LoadTileSet_bt) Then
Local TmpImageHandle
PNGTileSETURF = RequestFile("Select PNG TileSet")
NewImageName = StripAll(PNGTileSETURF)
TmpImageHandle = xLoadImage(PNGTileSETURF)
If TmpImageHandle > 0 Then
ClearAll()
TilesetImageHandle = TmpImageHandle
alShow(Convert_bt)
ImageButton = Alba.CreateButtonWithImage_al(Original_Win, TS.PNGTileSETURF, 5, 5, 850, 540, True) ; UpdateGraphics()
If IsPNG(TmpImageHandle) = False Then PixelSelectProcess()
End If
End If
'Convert to Seperated Pngs
If alTestClick(Convert_bt) Then
If TS.TilesetImageHandle > 0 Then
ClearConsol()
ConsoleMessage("Converting Began, Please Wait")
alShow(ForceStop_bt) ; alOnTop(ForceStop_bt)
'Free! Variables
TS.Pixel = Null
TS.Pixel = New Int[xImageWidth(TS.TilesetImageHandle) , xImageHeight(TS.TilesetImageHandle)]
ClearFolder(OutputURL)
For Local Image = EachIn images
xFreeImage(Image)
Next
Images = Null
Images = New Int[0]
'Create Negative Mask
ConsoleMessage("Creating Negative")
TempNegativeImageHandle = xCreateImage(xImageWidth(TS.TilesetImageHandle), xImageHeight(TS.TilesetImageHandle))
BuildEmptySpacesField(TS.TilesetImageHandle,,, True)
'Read PNGS
ConsoleMessage("Extracting PNGS")
Images = TS.ReadAllPngs(TS.TilesetImageHandle, TS.Pixel)
ConsoleMessage("~nConvertion Over")
'Save Images
Local URL:String = OutputURL, Counter
For Local Image = EachIn Images
Counter = Counter + 1
xSaveImage(Image, URL + NewImageName + " " + Counter + ".png")
xFreeImage(Image)
Next
alHide(Convert_bt)
alHide(ForceStop_bt)
OpenURL(OutputURL)
End If
End If
'Open OutputURL
If alTestClick(GotoFolder_TA) Then OpenURL(OutputURL)
Case Section_ChoosePixel
End Select
End Method
'------------------------------Sub Commands------------------------------------'
Method ReadPNG(ImageHandle, CurrentX = 0, CurrentY = 0, Pixel[,] Var)
Local X, Y, StartX, StartY, NewPixel[ximagewidth(imagehandle), ximageheight(imagehandle)]
Local LeftX, RightX, UpY, DownY
'Start
Local Coords:Coords_Class = New Coords_Class
Coords = GetFirstEmptyPoint(ImageHandle, Pixel)
If Coords.X = -1 Then Return 'End Of Trace
StartX = Coords.X
StartY = Coords.Y
LeftX = StartX
RightX = StartX
UpY = StartY
DownY = StartY
NewPixel[StartX, StartY] = OccupiedPix 'A Must
Pixel[StartX, StartY] = OccupiedPix 'Not Certain
Coords = Null
'Left To Right
For Y = StartY To xImageHeight(ImageHandle) - 1
For X = 0 To xImageWidth(ImageHandle) - 1
'Is UnChecked
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()
Next
Next
'Right To Left And Down To Up
For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1
For X = xImageWidth(ImageHandle) - 1 To 0 Step - 1
'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()
Next
Next
'Up To Down [All Seems To Work]
For X = 0 To xImageWidth(ImageHandle) - 1
For Y = 0 To xImageHeight(ImageHandle) - 1
'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()
Next
Next
'Down To Up
For X = 0 To xImageWidth(ImageHandle) - 1
For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1
'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()
Next
Next
'Write The Image
Local NewImage = Xcreateimage (RightX - LeftX, DownY - UpY)
For Y = UpY To DownY
For X = LeftX To RightX
If NewPixel[X, Y] = OccupiedPix Then xWritePixel(X - LeftX, Y - UpY, xReadPixel(X, Y, xImageBuffer(ImageHandle)), xImageBuffer(NewImage))
'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics(50)
Next
Next
Return NewImage
End Method
Method ReadAllPngs[] (ImageHandle, Pixel[,] Var)
Local Image[], NewImage, Counter
Repeat
NewImage = ReadPNG(ImageHandle,,, Pixel)
If NewImage = 0 Then
Return Image 'End Of Cycles
Else
Image = Image +[NewImage]
End If
Counter = Counter + 1
ConsoleMessage("Image Num " + Counter, False)
If Counter > 500 Then Return 'Max Limit
'Demo Version
If DemoVersion_flg = True Then
If Counter >= LimitingOutput_Val Then
Notify ("Free Version allows only up to 10 Images extraction")
Return Image
End If
End If
'Force Stop
If ForceStopFlg = True Then Return Image
Forever
End Method
Method HasAnOccupiedPointAroundHim(ImageHandle, X, Y, Pixel[,] Var)
'Checks Left Pixel
If X > 0 And Pixel[X - 1, Y] = OccupiedPix Then Return True
'Checks Right Pixel
If X < xImageWidth(ImageHandle) - 1 And Pixel[X + 1, Y] = OccupiedPix Then Return True
'ChecksUpPixel
If Y > 0 And Pixel[X, Y - 1] = OccupiedPix Then Return True
'ChecksDownPixel
If Y < xImageHeight(ImageHandle) - 1 And Pixel[X, Y + 1] = OccupiedPix Then Return True
'LeftUpPixelIsOccupied
If X > 0 And Y > 0 And Pixel[X - 1, Y - 1] = OccupiedPix Then Return True
'RightUpPixelIsOccupied
If X < xImageWidth(ImageHandle) - 1 And Y > 0 And Pixel[X + 1, Y - 1] = OccupiedPix Then Return True
'DownLeftPixelIsOccupied
If X > 0 And Y < xImageHeight(ImageHandle) - 1 And Pixel[X - 1, Y + 1] = OccupiedPix Then Return True
'DownRightPixelIsOccupied
If X < xImageWidth(ImageHandle) - 1 And Y < xImageHeight(ImageHandle) - 1 And Pixel[X + 1, Y + 1] = OccupiedPix Then Return True
End Method
Method GetFirstEmptyPoint:Coords_Class(ImageHandle, Pixel[,] Var)
Local X, Y, CRDS:Coords_Class
CRDS = New Coords_Class
For Y = 0 To xImageHeight(ImageHandle) - 1
For X = 0 To xImageWidth(ImageHandle) - 1
If Pixel[X, Y] = UnChecked Then
CRDS.X = X
CRDS.Y = Y
Return CRDS
End If
Next
Next
'NotFound
CRDS.X = -1
End Method
Method BuildEmptySpacesField(ImageHandle, CurrentX = 0, CurrentY = 0, Start = False)
Local X, Y, StartX, StartY
'Start
If Start = True Then
Local Coords:Coords_Class = New Coords_Class
Coords = GetFirstEmptyPixel(ImageHandle)
StartX = Coords.X
StartY = Coords.Y
Pixel[StartX, StartY] = OccupiedPix
Coords = Null
End If
'Left To Right
For Y = StartY To xImageHeight(ImageHandle) - 1
For X = StartX To xImageWidth(ImageHandle) - 1
'Is Empty
If PixelIsOccupied(xReadPixel(X, Y, xImageBuffer(ImageHandle))) = False Then
If HasAnEmptyPixelAroundHim(ImageHandle, X, Y) = True Then
Pixel[X, Y] = OccupiedPix
End If
End If
TimedUpdateGraphics()
Next
Next
'Right To Left
For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1
For X = xImageWidth(ImageHandle) - 1 To 0 Step - 1
'Is Empty
If PixelIsOccupied(xReadPixel(X, Y, xImageBuffer(ImageHandle))) = False Then
If HasAnEmptyPixelAroundHim(ImageHandle, X, Y) = True Then
Pixel[X, Y] = OccupiedPix
End If
End If
TimedUpdateGraphics()
Next
Next
'Up To Down
For X = 0 To xImageWidth(ImageHandle) - 1
For Y = 0 To xImageHeight(ImageHandle) - 1
'Is Empty
If PixelIsOccupied(xReadPixel(X, Y, xImageBuffer(ImageHandle))) = False Then
If HasAnEmptyPixelAroundHim(ImageHandle, X, Y) = True Then
Pixel[X, Y] = OccupiedPix
End If
End If
TimedUpdateGraphics()
Next
Next
'Down To Up
For X = 0 To xImageWidth(ImageHandle) - 1
For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1
'Is Empty
If PixelIsOccupied(xReadPixel(X, Y, xImageBuffer(ImageHandle))) = False Then
If HasAnEmptyPixelAroundHim(ImageHandle, X, Y) = True Then
Pixel[X, Y] = OccupiedPix
End If
End If
Next
TimedUpdateGraphics()
Next
End Method
Method HasAnEmptyPixelAroundHim(ImageHandle, X, Y)
'Checks Left Pixel
If LeftPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X - 1, Y] = OccupiedPix Then Return True
'Checks Right Pixel
If RightPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X + 1, Y] = OccupiedPix Then Return True
'ChecksUpPixel
If UpPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X, Y - 1] = OccupiedPix Then Return True
'ChecksDownPixel
If DownPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X, Y + 1] = OccupiedPix Then Return True
'LeftUpPixelIsOccupied
If LeftUpPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X - 1, Y - 1] = OccupiedPix Then Return True
'RightUpPixelIsOccupied
If RightUpPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X + 1, Y - 1] = OccupiedPix Then Return True
'DownLeftPixelIsOccupied
If DownLeftPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X - 1, Y + 1] = OccupiedPix Then Return True
'DownRightPixelIsOccupied
If DownRightPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X + 1, Y + 1] = OccupiedPix Then Return True
End Method
'------------------Check If Pixel Is Occupied----------------------'
'LeftPixelIsOccupied
Method LeftPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX > 0 Then
Return PixelIsOccupied(xReadPixel(CurrentX - 1, CurrentY, xImageBuffer(ImageHandle)))
Else
Return - 1
End if
End Method
'RightPixelIsOccupied
Method RightPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX < xImageWidth(ImageHandle) Then
Return PixelIsOccupied(xReadPixel(CurrentX + 1, CurrentY, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method
'UpPixelIsOccupied
Method UpPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentY > 0 Then
Return PixelIsOccupied(xReadPixel(CurrentX, CurrentY - 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method
'DownPixelIsOccupied
Method DownPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentY < xImageHeight(ImageHandle) Then
Return PixelIsOccupied(xReadPixel(CurrentX, CurrentY + 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method
'LeftUpPixelIsOccupied
Method LeftUpPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX > 0 And CurrentY > 0 Then
Return PixelIsOccupied(xReadPixel(CurrentX - 1, CurrentY - 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End if
End Method
'RightUpPixelIsOccupied
Method RightUpPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX < xImageWidth(ImageHandle) And CurrentY > 0 Then
Return PixelIsOccupied(xReadPixel(CurrentX + 1, CurrentY - 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End if
End Method
'DownLeftPixelIsOccupied
Method DownLeftPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX > 0 And CurrentY < xImageHeight(ImageHandle) Then
Return PixelIsOccupied(xReadPixel(CurrentX + 1, CurrentY + 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method
'DownRightPixelIsOccupied
Method DownRightPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX < xImageWidth(ImageHandle) And Currenty < xImageHeight(ImageHandle) Then
Return PixelIsOccupied(xReadPixel(CurrentX + 1, CurrentY + 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method
'----------------------------------------'
Method GetFirstOccupiedPoint:Coords_Class(Image)
Local I, J, CRDS:Coords_Class, Pixel
CRDS = New Coords_Class
For I = 0 To xImageWidth(Image) - 1
For J = 0 To xImageHeight(Image) - 1
Pixel = xReadPixel(I, J, xImageBuffer(Image))
If Pixel <> PNGPixelValue And Pixel <> 0 Then
CRDS.X = I
CRDS.Y = J
Return CRDS
End If
Next
Next
End Method
Method GetFirstEmptyPixel:Coords_Class(Image)
Local I, J, CRDS:Coords_Class, Pixel
CRDS = New Coords_Class
For I = 0 To xImageWidth(Image) - 1
For J = 0 To xImageHeight(Image) - 1
Pixel = xReadPixel(I, J, xImageBuffer(Image))
If Pixel = PNGPixelValue Or Pixel = 0 Then 'Or Pixel = 3750201 'not sure about the 0
CRDS.X = I
CRDS.Y = J
Return CRDS
End If
Next
Next
End Method
Method PixelIsOccupied(Pixel)
Return Pixel <> PNGPixelValue And Pixel <> 0 'And Pixel <> 3750201
End Method
Method ClearAll()
'Alba.ClearElement(Consol_Win)
If TilesetImageHandle > 0 Then xFreeImage(TilesetImageHandle) ;TilesetImageHandle = 0
If ImageButton > 0 Then alFreeElement(ImageButton) ; ImageButton = 0
End Method
'------------------------------------------------------------'
Field ZoomPixImage = xcreateimage(15, 15)
Method PixelSelectProcess()
Repeat
'Local X, Y
'xWritePixel(X, Y, $ffffffff, xImageBuffer(ZoomPixImage) xImageColor(
'xImageColor(ZoomPixImage, $ff, $ff, $ff)
If Alba.MouseOverElementArea(Original_Win) Then ShowThisIcon = Cross_Ico
BlinkQuickMessage("PLEASE SELECT BACKGROUND PIXEL")
'ConsoleMessage("[This Image is not a PNG, Please Select a background Pixel]")
UpdateGraphics()
If xKeyHit(xKEY_ESCAPE) Then Exit
Forever
'Add Zoom Pixel So You can Choose Well
End Method
End Type
Type Coords_Class
Field X
Field Y
End Type
Type PixelCounter_Class
Field Value
Field Amount
End Type
You can simply use the code of TomToad without affecting your Xors-stuff.
Just
Import brl.pixmap
and you gain access to LoadPixmap and TPixmap. if you need to load a PNG: import brl.pngloader
bye
Ron
Ok derron ill check it thanks
hi.. can anyone have to algorithm of turning a color pixel into a gray pixel in order to turn a color image into black and white image?
Im experimenting as we speak.. but im not sure im doing the algorithm right, so better ask.
when i read a pixel value i sometimes get a negative number..
so whats that means? and can i overcome it and turn all numbers into positive values for comparison
Read the integer value of the pixel color - split it into RGBA and use the algorithm of your choice to create grayscale versions of it.
There are different approaches as the conversion is using a kind of "perceived color" approach.
You could for example convert RGB into HSL and then set the "S" (saturation) to 0 and convert back your HSL to RGB.
Or you can use CIE_Lab colors which use a more psychological/pereceived color approach for "color distances". Easiest bet with satisfying results though, is the HSL<->RGB thing.
Algorithms can be found here:
https://github.com/GWRon/Dig/blob/master/base.util.color.bmx
It also lists the "not so good but still working":
'faster than using the RGB-HSL-RGB conversion
'but results are not exactly the same
Method AdjustSaturationRGB:TColor(percentage:Float = 0.0)
'convert relative param to absolute param
percentage = 1.0 + percentage
'long
local luminance:float = sqr(0.299 * r*r + 0.587 * g*g + 0.114 * b*b)
r = Min(255, Max(0, luminance + (r - luminance) * percentage))
g = Min(255, Max(0, luminance + (g - luminance) * percentage))
b = Min(255, Max(0, luminance + (b - luminance) * percentage))
return self
End Method
bye
Ron
The absolute easiest way once you split the rgb into components is to do this:
(R + G + B)/3 is the new value for r,g and b.
ok.. Thanks Derron and Matty
Ok ive solved my write pixel speed problem..
all i needed to do is to use lockbuffer than use command called writepixelfast and than unlock buffer again..
that was all the issue. cheers
@Hardcoal
Hello,
I saw your little program and I have one unrelated question.
Which library are you using for your GUI? I am interested in the GUI library if I will use it for my game.
Is this supposed to be programmed with BlitzMax?
Thank you.
this gui only works under Xors3D engine under blitzmax
so only if you are planning to use Xors3D you can use this GUI.
other than that, you better find another GUI . Cheers :)
I finally DId picture hidden in picture..
the hidden picture is on black and white but i can also make it colored in the future if i like.
You load two pictures and than press process and you will get the image inside image new image..
Note: if you transfer this image using whatsup or some medias that process the pixels this wont work..
I did anyway just for experimenting.. i was wondering if its possible.
I simply steal some bits from the main image and use it as gray scales for the hidden image..
please choose a bigger image as the visible image.. because if not it will get stuck..
i didnt fix this yet
https://drive.google.com/file/d/10vPfCDd73soh4_9nwqCy2FA4fcuSZnb4/view?usp=sharing
(https://i.imgur.com/UTdGVu4.jpg)
Ok i made the hidden Image In Color..
it was more complicated but i managed..
I only do this as a type of excersize ..
i learnt a lot from it..
now that i finished it can move on with life :)
https://drive.google.com/file/d/1qOWXd_3vUDjW-UmifU9dl3Ev7Fj29Ybg/view?usp=sharing
the main exacutable (supermain.exe) is not doing anything on my pc (Windows 10 64)
weird.. i got also windows 10 .. 64
maybe i missed one DLL .. ill check it
because it wont show you that it misses a dll , it just wont run..
checking..
ok i checked it. and all seems fine.. I have no idea at this point why its not working for you..
ill ask a friend to download it and see if he has issues too.
ok he had no issues..
but he uses windows 7 so.. I dont know ;)