Automated vCard writer (with photo)

Awesome, I was going to ask, but didn’t think you would.

I hope you don’t mind, I blew it up,
and it made you look like a character from Guess Who

image image

1 Like

Looks like I shouldn’t’ve :slight_smile:

Never gets old. :ok_hand:

1 Like

I’ve done some more research and testing, and I found a two ways to increase photo quality even more:

1/ Decrease the image saturation: the end result looks less colorful, but the size of the compressed image decreases significantly

2/ Change file format from JPEG to WEBP. I’ve done tests on a few Android cellphone, and it turns out they all support WEBP natively down to at least Android v5. And boy! is WEBP better than JPEG or what! For the same final size, a WEBP image has a higher resolution, and much fewer compression artifacts than a JPEG.

Here for example, a photo of our Glorious Leader, before (JPEG, 686 x 686, 315 KB) and after (WEBP, 60 x 60, 555 bytes - fits on an NTAG 216):

It looks fantastic on a cellphone. Fucking brilliant image format: it really blows JPEG out of the water.

So, here’s an updated version of my script, that does both JPEG and WEBP - but does WEBP by default. All you gotta do is stick your photo as a photo.jpg file, edit your information, and play around with the compression parameters until the NDEF fits on your tag. In addition to the packages listed in the first post of this thread, you’ll need the webp package (apt-get install webp should do the trick):

#!/bin/bash

### vCard information
FIRSTNAME=Joe
LASTNAME=Blow
TELEPHONE=(311)555-1212
EMAIL=joeblow@aol.com
PHOTO=./photo.jpg
NOTE=

### What type of photo encoding/compression to use (JPEG or WEBP)
PHOTO_ENCODING=WEBP

### Parameters for the final JPEG image to put in the vCard, if we do JPEG
JPEG_SIZE=52x52
JPEG_SATURATION=43
JPEG_QUALITY=73

### Parameters for the final WEBP image to put in the vCard, if we do WEBP
WEBP_SIZE=60x60
WEBP_SATURATION=56
WEBP_QUALITY=69

### Path to the various utilities we need
GUETZLI=./guetzli/bin/Release/guetzli
CWEBP=cwebp
NDEFTOOL=ndeftool
TAGTOOL="python3 nfcpy/examples/tagtool.py"
 


# Resize / desaturate the original photo
echo "Resizing the photo for JPEG"
convert $PHOTO -resize $JPEG_SIZE -modulate 100,$JPEG_SATURATION,100 \
	./photo_resized_for_jpeg.png

echo "Resizing the photo for WEBP"
convert $PHOTO -resize $WEBP_SIZE -modulate 100,$WEBP_SATURATION,100 \
	./photo_resized_for_webp.png

echo "Compressing the photo for JPEG"
$GUETZLI --quality $JPEG_QUALITY ./photo_resized_for_jpeg.png \
	./photo_compressed.jpg

echo "Compressing the photo for WEBP"
$CWEBP -q $WEBP_QUALITY ./photo_resized_for_webp.png -o \
	./photo_compressed.webp

# Create the .vcf file
echo "Creating the vCard file"

echo "BEGIN:VCARD" > vcard.vcf
echo "VERSION:2.1" >> vcard.vcf
echo "N:$LASTNAME;$FIRSTNAME" >> vcard.vcf
echo "TEL:$TELEPHONE" >> vcard.vcf
echo "EMAIL:$EMAIL" >> vcard.vcf

if [ $PHOTO_ENCODING = JPEG ];then
  B64ENCPHOTO=$(base64 -w0 ./photo_compressed.jpg)
else
  B64ENCPHOTO=$(base64 -w0 ./photo_compressed.webp)
fi
B64ENCPHOTO="PHOTO;ENCODING=BASE64;TYPE=$PHOTO_ENCODING:$B64ENCPHOTO"
echo $B64ENCPHOTO | head -c 73 >> vcard.vcf
for L in $(echo $B64ENCPHOTO | tail -c +74 | sed -e 's/.\{72\}/&\n/g'); do
  echo -en "\n $L" >> vcard.vcf
done
echo >> vcard.vcf

if [ "$NOTE" ];then
  echo "NOTE:$NOTE" >> vcard.vcf
fi

echo "END:VCARD" >> vcard.vcf

# Dump the size of the .vcf file, for information
VCARDSIZE=$(wc -c < vcard.vcf)
echo "vCard size: $VCARDSIZE bytes"

# Create the NDEF record
echo "Encapsulating the vCard into an NDEF record"
$NDEFTOOL load --pack vcard.vcf tn text/vcard id '' save --force vcard.ndef

# Dump the size of the NDEF file, for information
NDEFSIZE=$(wc -c < vcard.ndef)
echo "NDEF size: $NDEFSIZE bytes"

# Read the tag
echo "Reading the tag"
CARD_INFO=$($TAGTOOL)

# Make sure the tag is writable
if [ ! "$(echo $CARD_INFO | grep -i 'NDEF Capabilities.*writeable *= *yes')" ]; then
  echo "Tag is not writeable!"
  exit -1
fi

# Make sure there's enough room on the tag for the NDEF record
TCAPA=$(echo $CARD_INFO | sed -r 's/^.*NDEF Capabilities.*capacity *= *([0-9]+) byte.*$/\1/')
if [ $TCAPA -lt $NDEFSIZE ]; then
  echo "NDEF size exceeds the tag's capacity ($TCAPA bytes)!"
  exit -1
fi

# Ask the user if they really want to write the vCard on the tag
read -p "Write NDEF onto the tag [Y/N]? " YN
if [ "$YN" != "y" ] && [ "$YN" != "Y" ]; then
  echo "Aborting"
  exit 0
fi

# Write the NDEF file onto the tag
echo "Writing NDEF onto the tag"
$TAGTOOL load vcard.ndef

echo "All done!"

Sorry, Linux-only. I don’t have Windows.

5 Likes

That IS impressive, Amal doesn’t even look like a Guess Who™ character!

Nice work @anon3825968

Yeah I’m properly impressed by the quality for a half kilobyte image.

I didn’t think cellphones read anything other than JPEG and GIF for contact photos. But then I remembered Android is Google, and WEBP is also Google. I figured it would make sense for them to have Android support it. So I tried, and sure enough… tada!

1 Like

This is super cool, I plan to create and upload one tonight :slight_smile:

I wish I was smart enough to turn this into an automated webpage app thing…

Thanks again!!!

1 Like

Just a couple notes;

From a fresh Kali Live, to compile, you also need:
apt-get install libpng-dev
apt-get install pkg-config

In your updated script, you forgot the " " around the phone number and the script spits out an error because of the ( ) around the area code.

Lastly, because I’m a noob, the max size of the output file can be 888 bytes. Make sure you adjust the WEBP section of the quality settings, not just the top one. That threw me off for a few mins :slight_smile:

Sorry, I’m getting an error when trying to open the vCard on my Pixel 2

Ooh, well spotted. That one’s on me: I replaced my personal phone number with a generic one in the script before pasting it here and I didn’t check that it would work. I used the first fake number that came to my mind, but I currently live in Finland and there are no parens in phone numbers here :slight_smile: Sorry about that.

That’s the maximum size of the NDEF (more like 868 bytes for a NTAG216 in fact, because there are bytes used by the NDEF encapsulation and other reserved fields in the tag). But the actual image in binary format is much smaller, because it needs to be base64-encoded. Typically in the order of 5.5 kB before encoding.

Yes sorry again, I guess that wasn’t too clear. There’s a top PHOTO_ENCODING variable that selects whether you want JPEG or WEBP, and then two distinct quality settings. If PHOTO_ENCODING is set to WEBP, only the WEBP_* variables do anything.

Hmm now that’s strange.

There are two things your phone could choke on: either the version of the vCard format - which I set at 2.1 - or the WEBP encoding of the image.

vCard v2.1 dates back to 1996, so it should be supported. I chose it because that’s the format that has the fewer mandatory fields, to save as much space as possible. Also, it’s a sort of lowest common denominator, to ensure it’s compatible with just about anything. You could try vCard v3.0, but then you need to add other fields like FN and ADR for full compatibility. See here: https://www.evenx.com/vcard-3-0-format-specification

WEBP is a Google format that was created in 2010. Being a Google format, it’s highly likely to be understood natively by all Android phones since 2010. Yours was made in 2017: it most definitely should understand it. I myself tried it on Android versions from 5 to 10 without any issues, and I shared my own vCard with many people without any issues either. Maybe try to transfer the .webp image as-is onto the phone’s filesystem and open it directly with the photo viewer: if it displays it, there should be no issue with the image in the vCard, since it’s the same code that handlies both.

I can send you a ready-made .ndef file that I know works for sure, that you could try to write into a tag and try on your phone if you want, just to make sure there isn’t something odd with the Pixel 2. I wouldn’t think there is - it is a Google phone after all - but who knows.

Also, are you using the stock Android contact app?

I wish all noobs were as competent as you :slight_smile:

And also because of the capability container nonsense not making full use of the memory for NFC… it’s honestly pretty fucked up.

The nonsense only applies to chips with more than 1k though doesn’t it? The NTAG216 isn’t really concerned by this.

Also, aren’t most DT implants magic? If it’s magic, it should work everywhere with the power of magic :slight_smile:

magic-confetti

Once again, noob here, but I don’t think many are ‘magic’ (sorry if that was sarcasm), especially the NeXT (which I assume is a top seller?). Something about the magic ones being physically larger.

Something I wish I would have known more about when I got the NeXT, but no biggie

Yes, I can view it just fine, and if it’s OVER 50x50px I can add it to a vCard (it wants to give you the option to crop it before adding it, but can’t edit under 50x50px), but if you try to export it from there, it shows the vCard as being like 2k or something (probably the vCard v3 or whatever?).

Yes, all stock Google Pixel 2, no branding

Well shucks :stuck_out_tongue:
Just trying to help document as much as possible for other future noobs.

Okay here’s a corrected version. I removed the confusing JPEG bit (it just does WEBP compression) and I made sure it works this time :slight_smile: I also left the intermediate files it produces and the final NDEF file, in case you want to compare what it does on your machine.

Naturally, I’ve tested it and it works: the tag is an NTAG216, and it works fine on my Android 5, 7, 9 and 10 test phones.

vcard_writer_with_sample_information.zip (333.7 KB)

Let me know how this works for you.

No… read the section called Memory problems

Not sarcasm. There are some DT implants with magic chips in the sense that they can be configured to change personality or they have backdoor commands. But all DT implants are magic because they were lovingly crafted by Amal and they bring you joy. Also, they automatically expose you to the DT worldwide mind control field and it’s great, and there are no…no…no…no…no…no…no…side…side…side…side…effecttttttttsttststtsttstt&"#¤&%/

Yep, that works perfect. No idea what’s going on. I’ll retry it a few more times and get back to you with my findings.

I haven’t done too much digging yet, and I’m just comparing the jpeg+webp script, not your new one, but there are some differences in my output compared to yours.

Yours:

Mine:

What’s your implant? How much space does the script say is available on the chip when you run it?