python-fu gimp get items list - gimp

How can I get the list of items in an image using python-fu? I've tried searching for a similar function in Python Procedure Browser and google but I couldn't find any. (My end goal is to select a text item on a layer and convert it to a path)
Edit - Using GIMP version 2.8.2 on macOS Mojave

You don't list "items" in general. You list layers, channels, or paths, either using the PDB:
for lid in pdb.gimp_image_get_layers(image)
for cid in pdb.gimp_image_get_channels(image)
for vid in pdb.gimp_image_get_vectors(image)
or the attributes of the image object:
for l in image.layers
for c in image.channels
for v in image.vectors
The PDB calls return integer item IDs (use gimp._id2drawable(id)/gimp._id2vectors(id) to get the objects), while the image attributes are lists of gimp.Layer/gimp.Channel/gimp.Vector objects (and are therefore much simpler to work with).
To tell if a layer is a text layer, you have to use a PDB call: pdb.gimp_item_is_text_layer(layer)
You can iterate the text layers thus
for textlayer in [l for l in image.layers if pdb.gimp_item_is_text_layer(l)]`
To get the path from a text layer:
path=pdb.gimp_vectors_new_from_text_layer(image,layer)
Many sample Python scripts here and some more specialized in paths here.

Related

Is there a way to analyze OMS (Open Street Maps) pbf files for large areas (Germany) whithout running into memory issues?

my task is to create a database with all street names and town names in Germany. As this is a large query I chose to download the pbf file with the python pyrosm package. Once I unpack the data with OSM() and use get_network() I run into memory issues as the loaded DataFrame is to large. See here for roads (this works for smaller areas such as regions in germany):
from pyrosm import get_data
from pyrosm import OSM
import pandas as pd
#Downloading the germany Data
de = get_data("germany")
#Turning it into an OSM object
de_osm = OSM(de)
#Extracting all driving objects, e.g. roads
roads = osm_object.get_network(network_type="driving")
#Extract all road names and turning it into a list
road_names = pd.Series(roads.name).values
road_names = list(road_names)
I wanted to solve this problem with generator functions but I cant seem to iterate over the data like i would with a csv file. Here are my attempts that failed:
osm.object= (OSM(obj) for obj in de)
#Extracting all driving objects, e.g. roads
roads = osm_object.get_network(network_type="driving")
#Extract all road names and turning it into a list
road_names = pd.Series(roads.name).values
road_names = list(road_names)
Alternative:
def generator_osm():
for i in OSM(de).get_network(network_type="driving"):
yield i
res = generator_osm()
#Extract all road names and turning it into a list
road_names = list()
for i in res:
road_names = road_names.append(pd.Series(i.name).values)
Thank you in advance for any tipps you can provide :)
I would suggest to use pyosmium. It allows you to analyse osm files easily without having to deal with the geometry. I tried pyrosm a bit and I think it tries to create a road network when using .get_network(…), which is unnecessary if you only want to know what names the roads objects in your osm files have.
I took an example of the pyosmium documentation and applied it to collecting road names in a short example:
import osmium
from collections import Counter
# handler that processes your file
class RoadNameHandler(osmium.SimpleHandler):
def __init__(self):
super(RoadNameHandler, self).__init__()
self.road_names = []
def way(self, o):
if 'highway' in o.tags and 'name' in o.tags:
self.road_names.append(o.tags['name'])
# process file
h = RoadNameHandler()
h.apply_file("germany-latest.osm.pbf")
# some examples to print & count the names
print(h.road_names)
print(Counter(h.road_names))
print(len(h.road_names))
This script did not take more than 500-600 MB of memory, the pbf file had to be downloaded manually from Geofabrik.
P.S.: If you want to have a distinct list of the road names you can either use a Counter() or a set instead of the list for self.road_names.

How to get a path for script-fu function: gimp-drawable-edit-stroke-item

I am struggling with getting the actual path (or vector) object from an id. I want to stroke a path and the currently advised way of doing so seems to be the method gimp-drawable-edit-stroke-item. This needs an item as input. By the way I tried to find a list of all predefined types in script-fu but also didn't find anything. So I am not sure what the typ Item really is but it looks like you can pass a vector to it.
All I can find so far to identify a path is using (cadr(gimp-image-get-vectors p-image)) which seems to only give me an id. As the following (gimp-drawable-edit-stroke-item p-drawable (cadr(gimp-image-get-vectors p-image))) leads to an "Error: Invalid type for argument 2 to gimp-drawable-edit-stroke-item".
Having to navigate lists instead of using names for fields is the reason why I never bothered with Scheme/script-fu since Gimp can be scripted in Python.
This said, with my limited Lisp knowledge:
(gimp-image-get-vectors p-image) returns a (count (v1 v2 v3 ...)) list
so (cadr (gimp-image-get-vectors p-image)) returns the list, and not a single item of the list.
You can get the "active path" directly with (gimp-image-get-vectors p-image) (using the paths list doesn't tell you which path in the list is meant by the user anyway).
"I want to stroke a path"
Rather than gimp-drawable-edit-stroke-item, gimp-pencil (or gimp-brush) can do it:
(define (stroke-path drawable color width . path)
(gimp-context-set-line-miter-limit 5) ; default: 10, default mitre up to 60 pixels
(gimp-context-set-stroke-method STROKE-LINE) ; default STROKE-PAINT-METHOD
(gimp-context-set-line-cap-style CAP-BUTT) ; CAP-ROUND, CAP-SQUARE
(gimp-context-set-line-join-style JOIN-ROUND) ; JOIN-MITER, JOIN-ROUND, JOIN-BEVEL
(gimp-context-set-foreground color)
(gimp-context-set-line-width width) ; default: 6
(let ((vec (apply vector path)))
(gimp-pencil drawable (vector-length vec) vec)
)
)

"For all" using Apache Jenas rule engine

I'm currently working on some small examples about Apache Jena. What I want to show is universal quantification.
Let's say I have balls that each have a different color. These balls are stored within boxes. I now want to determine whether these boxes only contain balls that have the same color of if they are mixed.
So basically something along these lines:
SAME_COLOR = ∃x∀y:{y in Box a → color of y = x}
I know that this is probably not possible with Jena, and can be converted to the following:
SAME_COLOR = ∃x¬∃y:{y in Box a → color of y != x}
With "not exists" Jena's "NoValue" can be used, however, this does (at least for me) not work and I don't know how to translate above logical representations in Jena. Any thoughts on this?
See the code below, which is the only way I could think of:
(?box, ex:isA, ex:Box)
(?ball, ex:isIn, ?box)
(?ball, ex:hasColor, ?color)
(?ball2, ex:isIn, ?box)
(?ball2, ex:hasColor, ?color2)
NotEqual(?color, ?color2)
->
(?box, ex:hasSomeColors, "No").
(?box, ex:isA, ex:Box)
NoValue(?box, ex:hasSomeColors)
->
(?box, ex:hasSomeColors, "Yes").
A box with mixed content now has both values "Yes" and "No".
I've ran into the same sort of problem, which is more simplified.
The question is how to get a collection of objects or count no. of objects in rule engine.
Given that res:subj ont:has res:obj_xxx(several objects), how to get this value in rule engine?
But I just found a Primitive called Remove(), which may inspire me a bit.

mapping graduated symbols in arcpy for data with changing max value

I have a pyscript that I am working on and running into issues with the legend.
The goal of the script is to take a csv file with two columns (country, value) that I am joining to a world map based on country name. Once they are joined I turn it into a lyr file and then start to work on the mapping aspects of it.
I want to change the field being mapped to 'value' and then change the mapping to graduated symbols with 5 breaks (at 5,20,50,75,100 % of the max value in the map). The problem being that depending on what layer file is being used the max value changes. I have spent a lot of time searching for how to do this and have still come up short, there are probably some unnecessary bits to my code as well as I am now to python.
How can I get it to map based on graduated symbol based on 5 percent breaks with a changing max value?
Some of the code I have been working on below,
import os, sys, string, arcpy, arcpy.mapping, glob, arcgisscripting,time
from arcpy import env
call blank mxd file, set feature layer, Declare variables
mxd = arcpy.mapping.MapDocument(workspace/blank_4.mxd")
df = arcpy.mapping.ListDataFrames(mxd)[0]
'newname' is the layer file being used
sourceLayer = arcpy.mapping.Layer(newname)
Convert feature classes to layer objects
outLayer = str(newname)
curmap = workspace + filename + ".shp"
arcpy.MakeFeatureLayer_management(curmap, outLayer)
Save layer objects to layer files
LayerFile = str(outLayer) + ".lyr"
arcpy.SaveToLayerFile_management(outLayer, LayerFile)
Define variable for the new layer using LayerFile object
newlayer = arcpy.mapping.Layer(LayerFile)
Adds the new layer to top of TOC in the mxd doc map document
arcpy.mapping.AddLayer(df, newlayer, "TOP")
change the mapping field from country name to fert value
lyr = arcpy.mapping.ListLayers(mxd, newlayer, df)[0]
symbols = arcpy.mapping.Layer(C:\workspace\graduated_symbol2.lyr")
graduated symbols is a blank layer file where I created a legend with 5 breaks (5,20,50,75,100 %) but the range was created based on a max value of 22,000 and now when I run a file with a max value of 35,000 anything above 22,000 becomes blank.
How can I get it to purely work on % breaks, and have the 0/max range of the respective csv file be used??????
Update new layer with sybmology from the source layer
arcpy.ApplySymbologyFromLayer_management(lyr,symbols)
arcpy.mapping.UpdateLayer(df, lyr, symbols, True)
change symbology, colors, and breaks
if lyr.symbologyType == "GRADUATED_COLORS":
lyr.symbology.valueField = "value"
print lyr.symbology.numClasses #
Then I output this to a pdf, but that part is working.
Thanks!

Generating printable output within Squeak

I'd like to create a printable output file from within Squeak, for instance to create a report.
I've done a little Googling and I'm surprised by how little material in the way of examples relating to creating printable files exist. However, I've found a couple of classes class called PostscriptCanvas and EPSCanvas and a method within it called morphAsPostscript.
To try these classes out I created a tiny code example and my first workspace example was:
p := PasteUpMorph new.
p extent: 300#300.
p position: 20#20.
p borderColor: Color black.
p setProperty: #cornerStyle toValue: #rounded.
p openInWorld.
(FileStream newFileNamed: 'test1.ps') nextPutAll: (PostscriptCanvas morphAsPostscript: p)
unfortunately the above doesn't work and halts with doesnotUnderstand #pageBBox.
when I try the example again but this time using the EPSCanvas class:
p := PasteUpMorph new.
p extent: 300#300.
p position: 20#20.
p borderColor: Color black.
p setProperty: #cornerStyle toValue: #rounded.
p openInWorld.
(FileStream newFileNamed: 'test2.eps') nextPutAll: (EPSCanvas morphAsPostscript: p).
this time I generate output but the corners of the box aren't rounded in the eps file (they are rounded on the screen).
So, my questions are:
Am I on the right track as far as generating printable output or should I be using an alternative technique?
Why does the first example crash with doesnotUnderstand #pageBBox?
Why does the second example almost work but does not render the rounded corners?
Thanks
Kevin
It's not just Squeak - producing printable output is fearsomely difficult in any programming language. Whenever I've done project planning and people mention reports, I immediatel double (at least) the project estimates. Personally, I would recommend writing the data to a file in some well-known format such as XML or CSV and then use a report-writing package to produce the actual reports.
Sorry not to be more helpful!

Resources