Pixel Level Data

Moderator: Kathy_9

blendmo
Posts: 12
Joined: Tue Dec 18, 2018 6:38 am
operating_system: Windows 10
System_Drive: C
32bit or 64bit: 64 Bit
Corel programs: PSP 2019 Ultimate

Pixel Level Data

Post by blendmo »

Is it possible to get access to pixel-level-data through the API. I.e. traverse the array of pixels and access attributes such as color, transparency, or whether it is within a selection?
LeviFiction
Advisor
Posts: 6777
Joined: Thu Oct 02, 2008 1:07 pm
operating_system: Windows 10
System_Drive: C
32bit or 64bit: 64 Bit
motherboard: Alienware M17xR4
processor: Intel Core i7-3630QM CPU - 2_40GH
ram: 6 GB
Video Card: NVIDIA GeForce GTX 660M
sound_card: Sound Blaster Recon3Di
Hard_Drive_Capacity: 500GB
Corel programs: PSP: 8-2023
Location: USA

Re: Pixel Level Data

Post by LeviFiction »

No, and kind of yes.

In the strictest sense, no it's not possible. PSP offers no ability to get pixel level data. Much less any of its attributes. However, it is still possible to do what you want on at least some level.

For example, we cannot get the color of a pixel directly, what we have to do is use the eye-dropper to sample the color, and then we can use 'GetMaterial' to get the value of the currently selected material from the materials palette. At the same time, however, since the materials palette doesn't support transparency in normal color selection we cannot find out the transparency value of a pixel.

Here is a simple function that first saves your current material, samples a material from the image, grabs the color, then resets the material to defaults.

Code: Select all

def getColor(Environment, x, y):
    Material = App.Do( Environment, 'GetMaterial', {  'IsPrimary': True  })  #Gets current material before using eye-dropper
    App.Do( Environment, 'Eyedropper', {'Point': (x,y), 'SampleSize': 0, 'Material': App.Constants.MaterialRef.Foreground, 'ActiveLayerOnly': True, 'SampleColor': 0, })  #sample color
    color = App.Do( Environment, 'GetMaterial', {  'IsPrimary': True  })['Color']
    App.Do( Environment, 'SetMaterial', {  'IsPrimary': True,  'NewMaterial':Material  }) #Resets original material
    return color
I'm not sure how to grab the transparency of a pixel though. For transparency I suppose one could put a temporary layer underneath the pixel of a known color. Sample the normal color and the merged result with the eye-dropper and see how much the alpha played a roll in the math. I don't know the full math details myself, and I suck at math, so not entirely sure how that works but it would be one of the easiest ways.

Checking if a pixel is inside a selection is a bit harder, though not too hard. We can grab some basic information about a selection, like what kind of selection it is (raster, vector, floating, no selection at all) and where it starts and how big it is. We can also perform functions like editing the selection. So using these tools I can remove all of a selection around a single pixel and then test if a selection still exists. If it does, then that pixel was inside of a selection. If it's not then the pixel was not inside of a selection. And, of course, we restore the original selection at the end so we're back where we started from.

Code: Select all

from PSPApp import *
from PSPUtils import *

def ScriptProperties():
    return {
        'Author': u'',
        'Copyright': u'',
        'Description': u'',
        'Host': u'PaintShop Pro',
        'Host Version': u'22.00'
        }

def Do(Environment):
    # EnableOptimizedScriptUndo
    App.Do( Environment, 'EnableOptimizedScriptUndo', {'GeneralSettings': {}})

    print pointInSelection(Environment, 1127,505)
    print pointInSelection(Environment, 1128,505)



def pointInSelection(Environment, x, y, doc = App.TargetDocument):
    # '''This command removes giant rectangels around the selected point.
    # if a selection still exists then the point was inside the selection
    # however, if no selection exists, then the point was outside the selection'''

    #save original selection to get it back later
    selection = SaveSelection(Environment, doc)
    #restore selection
    selection.RestoreSelection()
    
    #get current selection rectangle
    Rect = App.Do( Environment, 'GetRasterSelectionRect' )

    #Convert Rect to full point values
    Rect = [Rect['Rect'][0][0], Rect['Rect'][0][1], Rect['Rect'][1]+Rect['Rect'][0][0],Rect['Rect'][2]+Rect['Rect'][0][1]]
    
    if x < Rect[0] or x > Rect[2] or y < Rect[1] or y > Rect[3]: #if point is outside selection rectangle, point is not in selection
	return False

    #remove all of the selections around the point
    removeRectFromSelection(Environment, Rect[0],Rect[1], x, Rect[3]) #Left |
    removeRectFromSelection(Environment, Rect[0],Rect[1], Rect[2], y) #Top   --
    removeRectFromSelection(Environment, x+1,Rect[1], Rect[2], Rect[3]) #Right   |
    removeRectFromSelection(Environment, Rect[0],y+1, Rect[2], Rect[3]) #Bottom__

    #check for selection
    Rect = App.Do( Environment, 'GetRasterSelectionRect' )

    #restore original seleciton
    selection.RestoreSelection()

    #return False if no selection remains, otherwise True
    return False if Rect['Type'] == 0 else True
 
def removeRectFromSelection(Environment, x, y,x2,y2):
    # Selection
    App.Do( Environment, 'Selection', {
            'General': {'Mode': App.Constants.SelectionOperation.Remove, 'Antialias': False, 'Feather': 0}, 
            'SelectionShape': App.Constants.SelectionShape.Rectangle, 
            'Start': (x,y), 
            'End': (x2,y2), 
            'SelectionStyle': App.Constants.SelectionStyle.Normal, 
            'GeneralSettings': {}
            })
blendmo
Posts: 12
Joined: Tue Dec 18, 2018 6:38 am
operating_system: Windows 10
System_Drive: C
32bit or 64bit: 64 Bit
Corel programs: PSP 2019 Ultimate

Re: Pixel Level Data

Post by blendmo »

Thank you for these solutions. They are very good. I had figured the eyedropper/getmaterial was a path, but in my testing it is very slow (primarily when the sampled color changes). But thanks for confirming that there really isn't a better way.

I like your approach with the selection. I had gone down a route of flood filling inside and outside the selection with different colors and then sampling (with the method above). This worked okay, but relied on the assumption of being able to fill the selection from the center of the GetRasterSelectionRect. I like your method better for finding selection pixels. It will work regardless of the shape of the selection.

Thanks again, and for such a quick response.
LeviFiction
Advisor
Posts: 6777
Joined: Thu Oct 02, 2008 1:07 pm
operating_system: Windows 10
System_Drive: C
32bit or 64bit: 64 Bit
motherboard: Alienware M17xR4
processor: Intel Core i7-3630QM CPU - 2_40GH
ram: 6 GB
Video Card: NVIDIA GeForce GTX 660M
sound_card: Sound Blaster Recon3Di
Hard_Drive_Capacity: 500GB
Corel programs: PSP: 8-2023
Location: USA

Re: Pixel Level Data

Post by LeviFiction »

Cassel here on the forums has a great method for finding the first pixel location in a selection. She's an excellent source for getting PSP to do fancy things, in my opinion.

What happens is she modifies the selection and removes all but the first row of selected pixels. The result is that the starting point of the selection is now also guaranteed to be the very first pixel in the selection. Just grab that location and you can use it with the fill tool to ensure you're always filling the selection.
blendmo
Posts: 12
Joined: Tue Dec 18, 2018 6:38 am
operating_system: Windows 10
System_Drive: C
32bit or 64bit: 64 Bit
Corel programs: PSP 2019 Ultimate

Re: Pixel Level Data

Post by blendmo »

Sounds like a very useful method.
DaverQ
Posts: 1
Joined: Sat Apr 25, 2020 10:41 am
operating_system: Windows 10
System_Drive: C
32bit or 64bit: 64 Bit

Re: Pixel Level Data

Post by DaverQ »

To speed up the mentioned method of picking each pixel with the eyedropper by a thousand fold make sure your materials "pallet" is not shown.
ilgk48
Posts: 63
Joined: Sun Apr 28, 2019 12:26 pm
operating_system: Windows 10
System_Drive: C
32bit or 64bit: 64 Bit
Corel programs: PaintShop PRO 2019 32bit

Re: Pixel Level Data

Post by ilgk48 »

Hi to all,
sorry for the probably stupi question but in the examples above I have seen:

selection = SaveSelection(Environment, doc)

and

selection.RestoreSelection

I suppose that SaveSelection and RestoreSelection are correlated with PSPutils ... but please, where can I find references for PSPutils ?
Thank you in advance.
Paolo
LeviFiction
Advisor
Posts: 6777
Joined: Thu Oct 02, 2008 1:07 pm
operating_system: Windows 10
System_Drive: C
32bit or 64bit: 64 Bit
motherboard: Alienware M17xR4
processor: Intel Core i7-3630QM CPU - 2_40GH
ram: 6 GB
Video Card: NVIDIA GeForce GTX 660M
sound_card: Sound Blaster Recon3Di
Hard_Drive_Capacity: 500GB
Corel programs: PSP: 8-2023
Location: USA

Re: Pixel Level Data

Post by LeviFiction »

The Scripting For Script Authors PDF (listed in the Scripting Resources topic at the top of the Scripting board) covers most if not all of the PSPUtils library.
ilgk48
Posts: 63
Joined: Sun Apr 28, 2019 12:26 pm
operating_system: Windows 10
System_Drive: C
32bit or 64bit: 64 Bit
Corel programs: PaintShop PRO 2019 32bit

Re: Pixel Level Data

Post by ilgk48 »

Many thanks 👍👍.