Reading and writing Windows "tags" with Python 3 - windows

In Windows image files can be tagged. These tags can be viewed and edited by right clicking on a file, clicking over to the Details tab, then clicking on the Tags property value cell.
I want to be able to read and write these tags using Python 3.
This is not EXIF data so EXIF solutions won't work. I believe it's part of the Windows Property System, but I can't find a reference in Dev Center. I looked into win32com.propsys and couldn't see anything in there either.
I wrote a program that does this once before, but I've since lost it, so I know it's possible. Previously I did it without pywin32, but any solution would be great. I think I used windll, but I can't remember.

Here is some sample code that's using the IPropertyStore interface through propsys:
import pythoncom
from win32com.propsys import propsys
from win32com.shell import shellcon
# get PROPERTYKEY for "System.Keywords"
pk = propsys.PSGetPropertyKeyFromName("System.Keywords")
# get property store for a given shell item (here a file)
ps = propsys.SHGetPropertyStoreFromParsingName("c:\\path\\myfile.jpg", None, shellcon.GPS_READWRITE, propsys.IID_IPropertyStore)
# read & print existing (or not) property value, System.Keywords type is an array of string
keywords = ps.GetValue(pk).GetValue()
print(keywords)
# build an array of string type PROPVARIANT
newValue = propsys.PROPVARIANTType(["hello", "world"], pythoncom.VT_VECTOR | pythoncom.VT_BSTR)
# write property
ps.SetValue(pk, newValue)
ps.Commit()
This code is pretty generic for any Windows property.
I'm using System.Keywords because that's what corresponds to jpeg's "tags" property that you see in the property sheet.
And the code works for jpeg and other formats for reading (GetValue) properties, but not all Windows codecs support property writing (SetValue), to it doesn't work for writing extended properties back to a .png for example.

Related

How to add link to source code in Sphinx

class torch.FloatStorage[source]
byte()
Casts this storage to byte type
char()
Casts this storage to char type
Im trying to get some documentation done, i have managed to to get the format like the one shown above, But im not sure how to give that link of source code which is at the end of that function!
The link takes the person to the file which contains the code,But im not sure how to do it,
This is achieved thanks to one of the builtin sphinx extension.
The one you are looking for in spinx.ext.viewcode. To enable it, add the string 'sphinx.ext.viewcode' to the list extensions in your conf.py file.
In summary, you should see something like that in conf.py
extensions = [
# other extensions that you might already use
# ...
'sphinx.ext.viewcode',
]
I'd recommend looking at the linkcode extension too. Allows you to build a full HTTP link to the code on GitHub or such like. This is sometimes a better option that including the code within the documentation itself. (E.g. may have stronger permission on it than the docs themselves.)
You write a little helper function in your conf.py file, and it does the rest.
What I really like about linkcode is that it creates links for enums, enum values, and data elements, which I could not get to be linked with viewcode.
I extended the link building code to use #:~:text= to cause the linked-to page to scroll to the text. Not perfect, as it will only scroll to the first instance, which may not always be correct, but likely 80~90% of the time it will be.
from urllib.parse import quote
def linkcode_resolve(domain, info):
# print(f"domain={domain}, info={info}")
if domain != 'py':
return None
if not info['module']:
return None
filename = quote(info['module'].replace('.', '/'))
if not filename.startswith("tests"):
filename = "src/" + filename
if "fullname" in info:
anchor = info["fullname"]
anchor = "#:~:text=" + quote(anchor.split(".")[-1])
else:
anchor = ""
# github
result = "https://<github>/<user>/<repo>/blob/master/%s.py%s" % (filename, anchor)
# print(result)
return result

Get the file type of a file using the Windows API

I am trying to identify when a file is PNG or JPG to apply it as a wallpaper. I am using the SHGetFileInfo to get the type name with the .szTypeName variable, but I just realized that it changes if the OS is in another language.
This is my code:
SHFILEINFOW fileInfo;
UINT sizeFile = sizeof(fileInfo);
UINT Flags = SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES;
// Getting file info to find out if it has JPG or PNG format
SHGetFileInfoW(argv[1], 0, &fileInfo, sizeFile, Flags);
This is how I am validating:
if (wcscmp(fileInfo.szTypeName, L"JPG File") == 0)
{
//Code here
}
When the OS is in spanish, the value changes to "Archivo JPG" so I would have to validate against all language, and does not make sense.
Any idea what other function I can use?
This API is meant to be used to produce a user-facing string representation for known file types1). It is not meant to be used to implement code logic.
More importantly, it doesn't try to parse the file contents. It works off of the file extension alone. If you rename an Excel workbook MySpreadsheet.xlsx to MySpreadsheet.png, it will happily report, that this is a "PNG File".
The solution to your problem is simple: You don't have to do anything, other than filtering on the file extension. Use PathFindExtension (or PathCchFindExtension for Windows 8 and above) to get the file extension from a fully qualified path name.
This can fail, in case the user appended the wrong file extension. Arguably, this isn't something your application should fix, though.
As an aside, you pass SHGFI_USEFILEATTRIBUTES to SHGetFileInfoW but decided to not pass any file attributes (second argument) to the call. This is a bug. See What does SHGFI_USEFILEATTRIBUTES mean? for details.
1) It is the moral equivalent of SHGFI_DISPLAYNAME. The only thing you can do with display names is display them.

How to print right-to-left report on odoo 8

I created a report in odoo 8 using RML, everything is good. but when i print the report, caracteres are printed from left to right. I tried with drawRightString but nothing does appears on the PDF.
I used openerp-rtl module but I noticed no changes.
What can i do to print it in RTL mode.
Generally people working on Right to left text on Arbic Language.
so in this case you just install the below python-bidi package :
https://pypi.python.org/pypi/python-bidi/
python-bidi package is helpful to set the Pure python implementation of the BiDi layout algorithm.
And also add the bidi directory in your OpenERP report dir and use the get_display(string) method for making your sting convert into the arbic formate and also use with the arabic_reshaper class
You can do some thing like
import arabic_reshaper
from bidi.algorithm import get_display
def get_arabic_string(string):
reshaped_text = arabic_reshaper.reshape(string)
bidi_text = get_display(reshaped_text)
return bidi_text
Just need to use the get_arbic_string function in your rml file and set it on rml and pass the sting as arbic formate.
just check another source :
pyfribidi for windows or any other bidi algorithm

In Python 3, best way to open an image stored in a list as a file object?

Using python 3.4 in linux and windows, I'm trying to create qr code images from a list of string objects. I don't want to just store the image as a file because the list of strings may change frequently. I want to then tile all the objects and display the resulting image on screen for the user to scan with a barcode scanner. For the user to know which code to scan I need to add some text to the qr code image.
I can create the list of image objects correctly and they are in a list and calling .show on these objects displays them properly but I don't know how to treat these objects as a file object to open them. The object that is given to the open function, (img_list[0] in my case), in my add_text_to_img needs to support read, seek and tell methods. When I try this as is I get an attribute error. I've tried BytesIO and StringIO but I get an error message that Image.open does not support buffer interface. Maybe I am not doing that part correctly.
I'm sure there are several ways to do this, but what is the best way to open in memory objects as a file object?
from io import BytesIO
import qrcode
from PIL import ImageFont, ImageDraw, Image
def make_qr_image_list(code_list):
"""
:param code_list: a list of string objects to encode into QR code image
:return: a list of image or some type of other data objects
"""
img_list = []
for item in code_list:
qr = qrcode.QRCode(
version=None,
error_correction=qrcode.ERROR_CORRECT_L,
box_size=4,
border=10
)
qr.add_data(item)
qr_image = qr.make_image(fit=True)
img_list.append(qr_image)
return img_list
def add_text_to_img(text_list, img_list):
"""
While I was working on this, I am only saving the first image. Once
it's working, I'll save the rest of the images to a list.
:param text_list: a list of strings to add to the corresponding image.
:param img_list: the list containing the images already created from
the text_list
:return:
"""
base = Image.open(img_list[0])
# img = Image.frombytes(mode='P', size=(164,164), data=img_list[0])
text_img = Image.new('RGBA', base.size, (255,255,255,0))
font = ImageFont.truetype('sans-serif.ttf', 10)
draw = ImageDraw.Draw(text_img)
draw.text((0,-20),text_list[0], (0,0,255,128), font=font)
# include some method to save the images after the text
# has been added here. Shouldn't actually save to a file.
# Should be saved to memory/img_list
output = Image.alpha_composite(base,text_img)
output.show()
if __name__ == '__main__':
test_list = ['AlGaN','n-AlGaN','p-AlGaN','MQW','LED AlN-AlGaN']
image_list = make_qr_image_list(test_list)
add_text_to_img(test_list, image_list)
im = image_list[0]
im.save('/my_save_path/test_image.png')
im.show()
Edit: I've been using python for about a year and I feel like this is a pretty common thing to do but I'm not even sure that I'm looking up/searching for the right terms. What topics would you search for to answer this? If anyone can post a link or two to what I need to read up on regarding this, that would be very appreciated.
You already have PIL image objects; qr.make_image() returns the (a wrapper around) the right type of object and you do not need to open them again.
As such, all you need to do is:
base = img_list[0]
and go from there.
You do need to match image modes when compositing; QR codes are black-and-white images (mode 1), so either convert that or use the same mode in your text_img image object. The Image.alpha_composite() operation does require that both images have an alpha channel. Converting the base is easy:
base = img_list[0].convert('RGBA')

VS2010 save array/collection data to a file while debugging

Is there some way to save array/list/collection data to a file while debugging in VS2010?
For example, in this code:
var addressGraphs = from a in context.Addresses
where a.CountryRegion == "Canada"
select new { a, a.Contact };
foreach(var ag in addressGraphs) {
Console.WriteLine("LastName: {0}, Addresses: {1}", ag.Contact.LastName.Trim(),
ag.Contact.Addresses.Count());
foreach(var Address in ag.Contact.Addresses) {
Console.WriteLine("...{0} {1}", Address.Street1, Address.City);
}
}
I'd like to set a breakpoint on the first 'foreach' line and then save the data in 'addressGraph' to a file.
where 'a' contains fields such as:
int addressID
string Street1
string City
<Ect.>
and 'Contact' contains fields such as:
string FirstName
string LastName
int contactID
<Ect.>
I'd like the file to contain the values of each of the fields for each item in the collection.
I don't see an obvious way to do this. Is it possible?
When your breakpoint is hit, open up the Immediate window and use Tools.LogCommandWindowOutput to dump the output to a file:
>Tools.LogCommandWindowOutput c:\temp\temp.log
?addressGraphs
>Tools.LogCommandWindowOutput /off
Note: You can use Log which is an alias for Tools.LogCommandWindowOutput
Update:
The > character is important. Also, the log alias is case sensitive.
See screenshot:
I also encoutered such a question, but in VS2013. I have to save a content of array while debugging.
For example, I need to save a content of double array named "trimmedInput". I do so:
Open QuickWatch Window from Debug menu (Ctrl+D, Q).
Put your variable in Expression and push Recalculate Button
You'll see all the values. Now you could select them all (Ctrl+A) and copy (Ctrl+C).
Paste (Ctrl+V) them in your favorite editor. Notepad, for example. And use them.
That's the simples way that I know. Without additional efforts. Hope that my description helps you!
P.S. Sorry for non English interface on screenshots. All necessary information are written in the text.
Something similar is possible with this method:
I built an extension method that I use in all of my projects that is a general and more powerful ToString() method that shows the content of any object.
I included the source code in this link:
https://rapidshare.com/files/1791655092/FormatExtensions.cs
UPDATE:
You just have to put FormatExtensions.cs in your project and change the Namespace of FormatExtensions to coincide to the base Namespace of your project. So when you are in your breakpoint you can type in your watch window:
myCustomCollection.ToStringExtended()
And copy the output wherever you want
On Visual studio Gallery search for: Object Exporter Extension.
be aware: as far as I worked with, it has a bug that block you from exporting object once in a while.
You can also call methods in the Immediate Window, and so I think your best bet would be to use an ObjectDumper object, like the one in the LINQ samples or this one, and then write something like this in the Immediate Window:
File.WriteAllText("myFileName.txt", ObjectDumper.Dump(addressGraph));
Depending on which ObjectDumper you decide to use, you may be able to customize it to suit your needs, and to be able to tell it how many levels deep you want it to dig into your object when it's dumping it.
Here's a solution that takes care of collections. It's a VS visualizer that will display the collection values in a grid while debugging as well as save to the clipboard and csv, xml and text files. I'm using it in VS2010 Ultimate. While I haven't tested it extensively, I have tried it on List and Dictionary.
http://tinyurl.com/87sf6l7
It handles the following collections:
•System.Collections classes
◦System.Collections.ArrayList
◦System.Collections.BitArray
◦System.Collections.HashTable
◦System.Collections.Queue
◦System.Collections.SortedList
◦System.Collections.Stack
◦All classes derived from System.Collections.CollectionBase
•System.Collections.Specialized classes
◦System.Collections.Specialized.HybridDictionary
◦System.Collections.Specialized.ListDictionary
◦System.Collections.Specialized.NameValueCollection
◦System.Collections.Specialized.OrderedDictionary
◦System.Collections.Specialized.StringCollection
◦System.Collections.Specialized.StringDictionary
◦All classes derived from System.Collections.Specialized.NameObjectCollectionBase
•System.Collections.Generic classes
◦System.Collections.Generic.Dictionary
◦System.Collections.Generic.List
◦System.Collections.Generic.LinkedList
◦System.Collections.Generic.Queue
◦System.Collections.Generic.SortedDictionary
◦System.Collections.Generic.SortedList
◦System.Collections.Generic.Stack
•IIS classes, as used by
◦System.Web.HttpRequest.Cookies
◦System.Web.HttpRequest.Files
◦System.Web.HttpRequest.Form
◦System.Web.HttpRequest.Headers
◦System.Web.HttpRequest.Params
◦System.Web.HttpRequest.QueryString
◦System.Web.HttpRequest.ServerVariables
◦System.Web.HttpResponse.Cookies
As well as a couple of VB6-compatible collections
In "Immediate Window" print following to get the binary dump:
byte[] myArray = { 02,01,81,00,05,F6,05,02,01,01,00,BA };
myArray
.Select(b => string.Format("{0:X2}", b))
.Aggregate((s1, s2) => s1 + s2)
This will print something like:
0201810005F60502010100BA
Change the '.Aggregate(...)' call to add blanks between bytes, or what ever you like.

Resources