Home Page

Windows Specific Exif Tag In Photos

Windows Specific Exif Tag In Photos

Tuesday, May 2, 2023 by Leon

While writing a custom batch application for a client to update standard EXIF tags for photos based on directory names I came across a particular challenge.

He asked if I could update the XPKeywords, XPAuthor, and XPTitle tags so that if someone downloaded one of his photos, right clicked on it, and chose Properties->Details the tags would display.

Since they are listed in the Exiv2 standard tags list I thought it would be a piece of cake. However it turns out that Windows doesn’t want a text string, it wants it in a byte array encoded in UCS2 (which I’ve never heard of before). Google/Github wasn’t much help, but I did find one reference to it, and through trial and error I came up with the following code which gets the job done. I’m not sure if this is the right way to do it, or the most efficient, but it works.

Basically, it wants a string comprised of the ascii value of each letter, separated by a zero, with three zeros at the end. Here is the C++ snippet that I’m using:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Note: allTags is a string with each tag separated by a space

string XPString;
string::iterator it; 

for ( it = allTags.begin() ; it != allTags.end() ; it++ ) { 
   if ( XPString.length() > 0 ) { 
       XPString += " 0 ";
   }   
   XPString += fmt::format("{:d}", *it);    
}   

XPString += " 000";
exifData[ "XPKeywords" ] = XPString;

Note: the above code uses the fmt C++ string formatting library. Even though I’m using c++20, since I’m cross compiling for some reason the new c++20 format library wasn’t available.


Logo by Pixel Perfect / Flat Icon

Cross Compiling Windows Applications

Cross Compiling Windows Applications

Saturday, Apr 15, 2023 by Leon

A recent job I landed through UpWork gave me the chance to set up a new application development workflow that I’ve been wanting to nail down which allows me to do all the development and testing of the windows applications on my Linux workstation.

Up till now I’ve been doing Windows development in a Windows10 VM utilizing Cygwin and wxWidgets. While very doable, I’m just not as efficient working in Windows. This comes from the majority of my last 20 years spent on Linux server and workstations.

So now I just have to:

  • set up the Makefile to call the cygwin toolchain executables for g++, gcc, ld, and windres
  • create a resource file for windres to set the APPINFO resources in the executable
  • use Wine to do inital debugging and testing
  • set up a shared folder with VMware to easily move executables and data to my WIN10 environment for further testing

Since this was a console application, one of the most tedious parts was to find just the right compile/link options to prevent Windows from opening a separate output window for the messages send to STDOUT.

For this particular project I also had to download and compile the Exiv2 Library and the Mini YAML parser for the config file.

In a nutshell the client had a large library of JPG photos dating back many years but were meticulously orgainized in a detailed folder structure. The goal of the application would be recursively descend a given directory structure, find all the JPG files, and add the TAGS to them based on parsing of the full directory path, including splitting tags where CamelCase, spaces, and numbers where found. All of the photos would then be loaded into Piwigo, which would use the embedded EXIF information to add the tags to the system when the files were imported.

Here is the Makefile I wound up using:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#
# Makefile for compiling windows console application
# on a Linux host
#
OBJS = exifupdate.o Yaml.o

# note - the ws2_32 and psapi libraries were needed
#        to be linked into the final application
#        by the Exiv2 library
LIBS = -lstdc++  -lpthread -lws2_32 -lpsapi

COPTS = -D__USE_MINGW_ANSI_STDIO -std=c++20 \
        -I exiv2/include/ -I exiv2/build

LDOPTS = -static -mconsole 
LD = i686-w64-mingw32-ld
CC = i686-w64-mingw32-gcc
CPP = i686-w64-mingw32-g++
WINDRES = i686-w64-mingw32-windres

manifest.o: manifest.rc
	$(WINDRES) $< -o $@

.cpp.o :
	$(CPP) $(COPTS) -c $< 

.c.o :
	$(CC) $(COPTS) -c $< 

exifupdate:	$(OBJS)
	$(CPP) $(OBJS) -o $@ exiv2/build/lib/libexiv2.a \
	$(LIBS) $(LDOPTS) manifest.o

clean:
	rm *.o
	rm *.exe

Let me know if you have any questions about how I set this up.


photo by Alex Andres from Pexels

Lost Boys Mobile Archive

Lost Boys Mobile Archive

Thursday, Mar 3, 2022 by Leon

The latest project that I’ve been indulging on is for the Lost Boys Center For Leadership Development and their Lost Boys Interview Project. If you aren’t familar with these groups please take a moment visit these sites. The latest iteration of this project is to come up with a mobile solution that would allow them to take everything they need to search and print the interview archives in a self containted unit to their new center in Juba, South Sudan.

Images Of The New Juba Center

Juba Center 2021

Juba Center 2021

Juba Center 2021

Juba Center 2021


Some of the challenges for this solution are:

  • lack of internet connectivity
  • intermittent and unreliable power
  • secure the archive data
  • use low cost computer solutions in case they are lost

The short version of the answer is going to be a web based search interface powered by a Raspbery Pi embedded computer. All of the archive data will stored in an encrypted database, and queries be able to be done on standard tablets and smartphones while at the center.

We will have a desktop laser printer for producing hard copy documents, along with a self contained Power Source to keep everything going. Some of the units we are considering are:

Each of these units should power everything for at least a couple hours, along with recharging the tables and phones and running a few lights when needed.

I’ve created a project page which I will update from time to time with details on the implimentation in case anyone is interested.

Stupid Linux Tricks

Stupid Linux Tricks

Monday, Nov 8, 2021 by Leon

It’s been a while since I’ve posted. Nothing earth shattering. Just been keeping busy with personal/family stuff and have picked up a few gigs on UpWork. From an IT standpoint I decided to try and make my work environment a little more efficient. Part of this was spurred on by spending an hour or two tracking down something that turned out to be the result of a keyboard-bounced character that I couldn’t spot easily. After that I decided to get a better keyboard, and set up a bluetooth mouse that I can take with me on the road.

While the keyboard is on order, and should be able to just be plugged in, the bluetooth mouse is something I’ve toyed with over the years but haven’t really had much success with.

As a little background, my laptop (a Lenovo X240) spends 95% of it’s time in a docking station next to my desk (and usually under a cat, but that’s another story). When I do take it on the road I find it annoying that brushing the trackpad or touchpoint devices have some undesired effects - especially since I’m using the Awesome Windows Manger. My windows and screens wind up flying around in the most undesireable ways. The local Officemax had a clearance on Logitech bluetooth mice so I picked one up and much to my surprise, the Linux support for it is much better than it was last time I tried it. The mouse automatically connects each time I reboot the computer.

Now when I’m on the road I can take the mouse with me, and if it’s turned on the following script that is run at boot time will automatically disable the trackpad and pogo stick on the laptop:

 1#!/usr/bin/tclsh
 2
 3set btMouse "Bluetooth Mouse M336"
 4set targetList [list "TPPS/2 IBM TrackPoin" "Synaptics TM2749-001"]
 5set disableList [list]
 6set gotBTMouse 0
 7
 8set inputpipe [open "| xinput list"]
 9while { [gets $inputpipe thisDevice] >= 0 } {
10	 set deviceName [string range $thisDevice 6 25]
11	 puts $deviceName
12	 if { $deviceName == $btMouse } {
13		 set gotBTMouse 1
14	 } elseif { [lsearch -exact $targetList $deviceName] != -1  } {
15		 puts $deviceName
16		 set thisId [string range $thisDevice \
17			   [expr [string first "id=" $thisDevice] + 3] \
18			   [expr [string first "id=" $thisDevice] + 4]]
19		 lappend disableList $thisId
20	 }
21}
22close $inputpipe
23
24if { $gotBTMouse } {
25	foreach thisDevice $disableList  {
26		exec xinput disable $thisDevice
27	}
28}
WebDAV Revisited

WebDAV Revisited

Friday, Jun 4, 2021 by Leon
One of my clients wanted me to set up a simple single page web site that she could access and edit via WebDAV on her Mac. While I haven’t dabbled in WebDAV for a few years, how hard could it be. I’m using NGINX, and there are a couple of modules for it, so I should be good to go. Or so I thought. While I was able to initially get it set up and working with linux utilities such as DavFS, and Litmus didn’t complain too bad, her Mac balked and would only open it in readonly mode, and couldn’t create any new directories. Read More
Upgraded File Upload Logic

Upgraded File Upload Logic

Saturday, Mar 6, 2021 by Leon
Recently one of my clients asked to have their file upload pages upgraded to show a progress bar and allow multiple files to be uploaded at once. After some DuckDuckGo-ing I settled on a solution based on FlowJS. While not the documentation was not totally intuitive, I was able to get things up and running pretty quickly. Besides the above link, I found a number of tutorials online, but this one was most helpful, including pointing me to the simple PHP Based Server to handle the uploads on the other end. Read More
Docker Mini Server / AWS Elastic Beanstalk

Docker Mini Server / AWS Elastic Beanstalk

Saturday, Sep 5, 2020 by Leon
I haven’t gotten into Docker much yet, even thought it’s had quite the buzz over the past few years. As both part of a proposal for a prospective client, along with doint a proof of concept, I put together a docker image based on Alpine Linux, utilizing ClamAV/Freshclam and Darkhttpd to provide a local mirror of ClamAV virus definitions. There was a bit of a learning curve to get all the moving pieces to work togther, but I think it turned out pretty well. Read More
What, Another Web Framework?

What, Another Web Framework?

Tuesday, May 12, 2020 by Leon
I’ve been developing applications for the web since the dawn or time (or at least the dawn of the internet). Everything from Server Side Includes (SSI), Perl (known as the duct tape of the internet), and PHP. However, I feel that something is lacking. I feel that PHP is just too bloated for what I need it to do, and don’t get me started on some of the legacy applications (such as Wordpress). Read More
Linode Object Storage

Linode Object Storage

Thursday, May 7, 2020 by Leon
So I recently found that Linode began offering S3 compatible object storage. Upon reading the documentation I found that it had the one options that pushed me to Rackspace Cloudfiles. Namely, it has an api to create a time-limited public link to individual files. This is what has been driving me to Rackspace Cloudfiles (along with their CDN) rather than Amazon S3. I also preferred the Rackspace pricing structure, which was much more straight forward than Amazon. Read More
Linux Live CD

Linux Live CD

Wednesday, Oct 9, 2019 by Leon
While trying to get my new laptop set up I used my normal procedures - namely using a USB->SATA connector to format the new drive, copy everything over, then booting a livecd with the drive in the new laptop in order to set up grub. That didn’t work so well. Up till now I’ve been using the Finnix live cd since it was the one linode uses. However, when I try to boot the new laptop with it, it doesn’t boot up properly (namely, it didn’t detect the new SSD drive). Read More
MYSQL Upgrade Remnamts / Dump Error

MYSQL Upgrade Remnamts / Dump Error

Monday, Apr 30, 2018 by Leon
While doing some maintenance and upgrading a backup server I noticed that the mysql dumps that are done before rsyncing daily were too small. We had just a production database over to this server a few weeks ago, and I was assuming that the dumps were happening since I wasn’t getting an error in the logs. This was on a machine we inherited from another IT provider, and it turns out that the mysql database had been languishing for a while and wasn’t updated after a mysql upgrade some time in the past. Read More
Connecting TCL To MS SQL Server (Linux) (Continued)

Connecting TCL To MS SQL Server (Linux) (Continued)

Saturday, Oct 21, 2017 by Leon
After a couple weeks of development, debugging, and testing, the revised scripts have been put into production. We just came across a couple of finer points that we had to word around. I’m guessing that these may be resolved in the future by switching to TDBC. In the previous post on this topic I mentioned that we had to use a connection string/dsn instead of a username and password. That wasn’t too bad to figure out. Read More
Connecting TCL To MS SQL Server (Linux)

Connecting TCL To MS SQL Server (Linux)

Sunday, Oct 8, 2017 by Leon
One of my clients called up asking to have an old data loader script (written in TCL) updated to post to MS SQL Server as well as to the legacy Postgres server. I was kind of surprised how easy it was. I started off with information from the MS SQL Server page on the TCL/Tk Wiki. Originally I was planning on using the TDBC package for connecting (which is the current standard), but the target server only has TCL8. Read More
Trying Out New PHP Framework (Flight)

Trying Out New PHP Framework (Flight)

Wednesday, Sep 20, 2017 by Leon
We have a couple of large web projects on deck (one of which is PixelTin), and I’m really not looking forward to coding them from scratch. I’ve tried a few full blown CMS system, and PHP frameworks, which really seem to be overkill. That being said, I decided to give Flight a try. While I didn’t want to code everything from the ground up, I also thought that something like Symphony or Wordpress would be too large, cumbersome, and overkill for what I needed to do - namely code the backend to an admin template. Read More
Digital Signage at Sabotencon 2017

Digital Signage at Sabotencon 2017

Wednesday, Sep 6, 2017 by Leon
This year at Sabotencon marked chibi-neko’s third convention with our raspberry pi based digital signage. We added a couple of new features, and come up with a list of to-do’s. A little background info is in order first. Since these conventions charge an arm and a leg for power (something like $100/day plus setup fees last time I checked) we had to come up with something that was portable, fairly low power, and not take up too much room. Read More