Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XMP face tag support #744

Open
bobosch opened this issue Oct 11, 2015 · 4 comments
Open

XMP face tag support #744

bobosch opened this issue Oct 11, 2015 · 4 comments
Labels
enhancement feature request

Comments

@bobosch
Copy link

bobosch commented Oct 11, 2015

Face thumbnails improves the ancestors chart. But it's a exhausting work to create all these face thumbnails. Another difficulty is to use always the same aspect ratio to get a consistent look of the charts with images.

I'm using Google's Picasa to manage my pictures. Picasa can automatically mark faces on a photo. If you have enabled the "Store name tags in photo" option
picasasavetags
Picasa stores this information in the file as XMP tag. The information also includes position, width and height of the face
facetags
By the way: The selections have always the same AR (and the nose in the middle ;-) )...

It would be a great help, if the media management would use this information to create additional thumbnails for each individual. If the media object is linked to a person, it should display the face thumbnail instead of the thumbnail of the full image.

If a photo has multiple face tags, a match algorithm is needed. Comparing the name should be enough, otherwise the additional information, which face tag belongs to which person has to be saved in the gedcom file. But I have no idea how. Perhaps as reference on the individual

0 @I1@ INDI
1 NAME Robert /Heel/
1 OBJE @M1@
2 REFN Robert Heel
3 TYPE Face
@bobosch
Copy link
Author

bobosch commented Oct 12, 2015

I've wrote a function to create the image thumbnails from a .jpg file

<?php
var_dump(create_face_thumbnails('data/media/family.jpg'));

function create_face_thumbnails($file) {
    $xmp_data=get_xmp_tag_from_file($file);

    if($xmp_data) {
        $faces=get_face_data_from_xmp_tag($xmp_data);

        if($faces) {
            $image=imagecreatefromjpeg($file);
            $info=array(
                'x'=>imagesx($image),
                'y'=>imagesy($image),
            );
            $path_parts=pathinfo($file);
            $base=$path_parts['dirname'].'/'.$path_parts['filename'].' ';

            foreach($faces as $name=>$face) {
                $rect=get_face_coordinates($face,$info);
                if($rect) {
                    $crop=imagecrop($image,$rect);
                    $exif=exif_read_data($file);
                    $crop=rotate_image_by_exif($crop,$exif);
                    $thumb=imagescale($crop,100);
                    imagejpeg($thumb,$base.$name.'.jpg');
                    $rects[$name]=$rect;
                }
            }

            return $rects;
        }
    }
}

function get_xmp_tag_from_file($file) {
    $content=file_get_contents($file);
    $xmp_data_start=strpos($content, '<x:xmpmeta');
    $xmp_data_end=strpos($content, '</x:xmpmeta>');
    $xmp_length=$xmp_data_end - $xmp_data_start;
    $xmp_data=substr($content, $xmp_data_start, $xmp_length + 12);

    return $xmp_data ;
}

function get_face_data_from_xmp_tag($xmp_data) {
    $faces=array();
    $name='';

    $xml_parser=xml_parser_create('UTF-8');
    xml_parser_set_option($xml_parser,XML_OPTION_SKIP_WHITE,0);
    xml_parser_set_option($xml_parser,XML_OPTION_CASE_FOLDING,0);
    xml_parse_into_struct($xml_parser, $xmp_data, $vals, $index);
    xml_parser_free($xml_parser);

    foreach($vals as $val) {
        switch($val['tag']){
            case 'rdf:Description':
                if($val['type']=='open' && !empty($val['attributes']['mwg-rs:Name']) && $val['attributes']['mwg-rs:Type']=='Face') {
                    $name=trim($val['attributes']['mwg-rs:Name']);
                }
                if($val['type']=='close') {
                    $name='';
                }
                break;
            case 'mwg-rs:Area':
                if($val['type']='complete' && $name) {
                    $faces[$name]=$val['attributes'];
                }
                break;
        }
    }

    return $faces;
}

function get_face_coordinates($face,$info) {
    if($face['stArea:unit']=='normalized') {
        $rect=array(
            'x'=>intval(round($info['x']*($face['stArea:x']-$face['stArea:w']/2))),
            'y'=>intval(round($info['y']*($face['stArea:y']-$face['stArea:h']/2))),
            'width'=>intval(round($info['x']*$face['stArea:w'])),
            'height'=>intval(round($info['y']*$face['stArea:h'])),
        );

        return $rect;
    }
}

function rotate_image_by_exif($image,$exif) {
    if($exif['Orientation']) {
        switch($exif['Orientation']) {
            case 2:
                imageflip($image,IMG_FLIP_VERTICAL);
                break;
            case 3:
                $image=imagerotate($image,180,0);
                break;
            case 4:
                imageflip($image,IMG_FLIP_HORIZONTAL);
                break;
            case 5:
                $image=imagerotate($image,270,0);
                imageflip($image,IMG_FLIP_VERTICAL);
                break;
            case 6:
                $image=imagerotate($image,270,0);
                break;
            case 7:
                $image=imagerotate($image,90,0);
                imageflip($image,IMG_FLIP_VERTICAL);
                break;
            case 8:
                $image=imagerotate($image,90,0);
                break;
        }
    }

    return $image;
}
?>

@bobosch
Copy link
Author

bobosch commented Apr 10, 2016

You can find an implementation on https://github.com/bobosch/webtrees

@marku5
Copy link
Contributor

marku5 commented Apr 11, 2019

@UksusoFF
Copy link
Contributor

Hi @bobosch
I recently added your code example to master branch in my extension (yep this is same is @marku5 link but renamed).
If you still want see face tags in webtrees please try it :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement feature request
Projects
None yet
Development

No branches or pull requests

4 participants