5 SGN::Image - SGN Images
9 This class provides database access and store functions as well as
10 image upload and certain image manipulation functions, such as image
11 file type conversion and image resizing; and functions to associate
12 tags with the image. Note that this was forked off from the insitu
13 image object. The insitu database needs to be re-factored to use this
16 The philosophy of the image object has changed slightly from the
17 Insitu::Image object. It now stores the images in a directory
18 specified by the conf object parameter "static_datasets_dir" plus
19 the conf parameter "image_dir" plus the directory name "image_files"
20 for the production server and the directory "image_files_sandbox" for
21 the test server. In those directories, it creates a subdirectory for
22 each image, with the subdirectory name being the corresponding image
23 id. In that directory are then several files, the originial image file
24 with the orignial name, the converted image into jpg in the standard
25 image sizes: large, medium, small and thumbnail with the names:
26 large.jpg, medium.jpg, small.jpg and thumbnail.jpg . All other
27 metadata about the image is stored in the database.
31 Lukas Mueller (lam87@cornell.edu)
32 Naama Menda (nm249@cornell.edu)
35 =head1 MEMBER FUNCTIONS
37 The following functions are provided in this class:
44 use File
::Path
'make_path';
45 use File
::Temp qw
/ tempfile tempdir /;
46 use File
::Copy qw
/ copy move /;
47 use File
::Basename qw
/ basename /;
49 use CXGN
::DB
::Connection
;
51 use CXGN
::Metadata
::Metadbdata
;
53 use CatalystX
::GlobalContext
'$c';
55 use base qw
| CXGN
::Image
|;
59 Usage: my $image = SGN::Image->new($dbh)
62 Args: a database handle, optional identifier
63 Side Effects: an empty object is returned.
64 a database connection is established.
70 my ( $class, $dbh, $image_id, $context ) = @_;
73 my $self = $class->SUPER::new
(
74 dbh
=> $dbh || $context->dbc->dbh,
75 image_id
=> $image_id,
76 image_dir
=> $context->get_conf('static_datasets_path')."/".$context->get_conf('image_dir'),
79 $self->config( $context );
88 Usage: $self->get_image_url($size)
89 Desc: get the url for the image with a given size
90 Ret: a url for the image
91 Args: size (large, medium, small, thumbnail, original)
101 if( $self->config->test_mode && ! -e
$self->get_filename($size) ) {
102 # for performance, only try to stat the file if running in
103 # test mode. doing lots of file stats over NFS can actually be
105 return '/img/image_temporarily_unavailable.png';
108 my $url = join '/', (
110 $self->config()->get_conf('static_datasets_url'),
111 $self->config()->get_conf('image_dir'),
112 $self->get_filename($size, 'partial'),
120 Usage: $image->process_image($filename, "stock", 234);
121 Desc: creates the image and associates it to the type and type_id
123 Args: filename, type (experiment, stock, fish, locus, organism) , type_id
124 Side Effects: Calls the relevant $image->associate_$type function
131 my ($filename, $type, $type_id) = @_;
133 $self->SUPER::process_image
($filename);
135 if ( $type eq "experiment" ) {
136 #print STDERR "Associating experiment $type_id...\n";
137 $self->associate_experiment($type_id);
139 elsif ( $type eq "stock" ) {
140 #print STDERR "Associating stock $type_id...\n";
141 $self->associate_stock($type_id);
143 elsif ( $type eq "fish" ) {
144 #print STDERR "Associating to fish experiment $type_id\n";
145 $self->associate_fish_result($type_id);
147 elsif ( $type eq "locus" ) {
148 #print STDERR "Associating to locus $type_id\n";
149 $self->associate_locus($type_id);
151 elsif ( $type eq "organism" ) {
152 $self->associate_organism($type_id);
154 elsif ( $type eq "cvterm" ) {
155 $self->associate_cvterm($type_id);
158 elsif ( $type eq "test") {
159 # need to return something to make this function happy
164 warn "type $type is not recognized as one of the legal types. Not associating image with any object. Please check if your loading script links the image with an sgn object! \n";
169 =head2 config, context, _app
171 Get the Catalyst context object we are running with.
176 my ($self,$obj) = @_;
178 $self->{configuration_object
} = $obj if $obj;
180 return $self->{configuration_object
};
185 =head2 get_img_src_tag
190 Args: "large" | "medium" | "small" | "thumbnail" | "original" | "tiny"
197 sub get_img_src_tag
{
200 my $url = $self->get_image_url($size);
201 my $name = $self->get_name();
202 if ( $size && $size eq "original" ) {
204 my $static = $self->config()->get_conf("static_datasets_url");
209 . "\"><img src=\"$static/images/download_icon.png\" border=\"0\" alt=\""
213 elsif ( $size && $size eq "tiny" ) {
217 . "\" width=\"20\" height=\"15\" border=\"0\" alt=\""
225 . "\" border=\"0\" alt=\""
231 =head2 get_temp_filename
242 sub get_temp_filename
{
244 return $self->{temp_filename
};
248 =head2 set_temp_filename
259 sub set_temp_filename
{
261 $self->{temp_filename
} = shift;
264 =head2 apache_upload_image
268 Usage: my $temp_file_name = $image->apache_upload_image($apache_upload_object);
270 Ret: the name of the intermediate tempfile that can be
271 used to access down the road.
272 Args: an apache upload object
273 Side Effects: generates an intermediate temp file from an apache request
274 that can be handled more easily. Adds the remote IP addr to the
275 filename so that different uploaders don\'t clobber but
276 allows only one upload per remote addr at a time.
277 Errors: change 11/30/07 - removes temp file if already exists
278 # returns -1 if the intermediate temp file already exists.
279 # this probably means that the submission button was hit twice
280 # and that an upload is already in progress.
285 sub apache_upload_image
{
288 ### deanx jan 03 2007
289 # Adjust File name if using Windows IE - it sends whole paht; drive letter, path, and filename
291 if ( $ENV{HTTP_USER_AGENT
} =~ /msie/i ) {
292 my ( $directory, $filename ) = $upload->filename =~ m/(.*\\)(.*)$/;
293 $upload_filename = $filename;
296 $upload_filename = $upload->filename;
299 my $upload_fh = $upload->fh;
302 $self->config()->get_conf("basepath") . "/"
303 . $self->config()->get_conf("tempfiles_subdir")
305 . $ENV{REMOTE_ADDR
} . "-"
308 my $ret_temp_file = $self->upload_image($temp_file, $upload_fh);
309 return $ret_temp_file;
314 sub upload_zipfile_images
{
316 my $file_member = shift;
318 my $filename = $file_member->fileName();
320 my $zipfile_image_temp_path = $self->config()->get_conf("basepath") . $self->config()->get_conf("tempfiles_subdir") . "/temp_images/photos";
321 make_path
($zipfile_image_temp_path);
323 $self->config()->get_conf("basepath")
324 . $self->config()->get_conf("tempfiles_subdir")
327 system("chmod 775 $zipfile_image_temp_path");
328 $file_member->extractToFileNamed($temp_file);
329 print STDERR
"Temp Image: ".$temp_file."\n";
336 my $temp_file = shift;
337 my $upload_fh = shift;
339 ### 11/30/07 - change this so it removes existing file
341 # # only copy file if it doesn't already exist
343 if ( -e
$temp_file ) {
347 open UPLOADFILE
, '>', $temp_file or die "Could not write to $temp_file: $!\n";
350 while (<$upload_fh>) {
352 #warn "Read another chunk...\n";
356 warn "Done uploading.\n";
361 =head2 associate_stock
363 Usage: $image->associate_stock($stock_id);
364 Desc: associate a Bio::Chado::Schema::Result::Stock::Stock object with this image
365 Ret: a database id (stock_image_id)
372 sub associate_stock
{
374 my $stock_id = shift;
376 my $username = $self->config->can('user_exists') ?
$self->config->user->get_object->get_username : $self->config->username;
378 my $metadata_schema = $self->config->dbic_schema('CXGN::Metadata::Schema');
379 my $metadata = CXGN
::Metadata
::Metadbdata
->new($metadata_schema, $username);
380 my $metadata_id = $metadata->store()->get_metadata_id();
382 my $q = "INSERT INTO phenome.stock_image (stock_id, image_id, metadata_id) VALUES (?,?,?) RETURNING stock_image_id";
383 my $sth = $self->get_dbh->prepare($q);
384 $sth->execute($stock_id, $self->get_image_id, $metadata_id);
385 my ($stock_image_id) = $sth->fetchrow_array;
386 return $stock_image_id;
394 Usage: $image->get_stocks
395 Desc: find all stock objects linked with this image
396 Ret: a list of Bio::Chado::Schema::Result::Stock::Stock
403 my $schema = $self->config->dbic_schema('Bio::Chado::Schema' , 'sgn_chado');
405 my $q = "SELECT stock_id FROM phenome.stock_image WHERE image_id = ? ";
406 my $sth = $self->get_dbh->prepare($q);
407 $sth->execute($self->get_image_id);
408 while (my ($stock_id) = $sth->fetchrow_array) {
409 my $stock = $schema->resultset("Stock::Stock")->find( { stock_id
=> $stock_id } ) ;
410 push @stocks, $stock;
414 =head2 associate_individual
416 Usage: DEPRECATED, Individual table is not used any more . Please use stock instead
417 $image->associate_individual($individual_id)
418 Desc: associate a CXGN::Phenome::Individual with this image
419 Ret: a database id (individual_image)
426 sub associate_individual
{
428 my $individual_id = shift;
429 warn "DEPRECATED. Individual table is not used any more . Please use stock instead";
430 my $query = "INSERT INTO phenome.individual_image
431 (individual_id, image_id) VALUES (?, ?)";
432 my $sth = $self->get_dbh()->prepare($query);
433 $sth->execute($individual_id, $self->get_image_id());
435 my $id= $self->get_currval("phenome.individual_image_individual_image_id_seq");
440 =head2 get_individuals
442 Usage: DEPRECATED. Use the stock table .
443 $self->get_individuals()
444 Desc: find associated individuals with the image
445 Ret: list of 'Individual' objects
452 sub get_individuals
{
454 warn "DEPRECATED. Individual table is not used any more . Please use stock instead";
455 my $query = "SELECT individual_id FROM phenome.individual_image WHERE individual_image.image_id=?";
456 my $sth = $self->get_dbh()->prepare($query);
457 $sth->execute($self->get_image_id());
459 while (my ($individual_id) = $sth->fetchrow_array()) {
460 my $i = CXGN
::Phenome
::Individual
->new($self->get_dbh(), $individual_id);
461 if ( $i->get_individual_id() ) { push @individuals, $i; } #obsolete individuals should be ignored!
467 =head2 associate_experiment
469 Usage: $image->associate_experiment($experiment_id);
470 Desc: associate and image with and insitu experiment
478 sub associate_experiment
{
480 my $experiment_id = shift;
481 my $query = "INSERT INTO insitu.experiment_image
482 (image_id, experiment_id)
484 my $sth = $self->get_dbh()->prepare($query);
485 $sth->execute($self->get_image_id(), $experiment_id);
486 my $id= $self->get_currval("insitu.experiment_image_experiment_image_id_seq");
491 =head2 get_experiments
495 Ret: a list of CXGN::Insitu::Experiment objects associated
503 sub get_experiments
{
505 my $query = "SELECT experiment_id FROM insitu.experiment_image
507 my $sth = $self->get_dbh()->prepare($query);
508 $sth->execute($self->get_image_id());
509 my @experiments = ();
510 while (my ($experiment_id) = $sth->fetchrow_array()) {
511 push @experiments, CXGN
::Insitu
::Experiment
->new($self->get_dbh(), $experiment_id);
516 =head2 associate_fish_result
518 Usage: $image->associate_fish_result($fish_result_id)
519 Desc: associate a CXGN::Phenome::Individual with this image
527 sub associate_fish_result
{
529 my $fish_result_id = shift;
530 my $query = "INSERT INTO sgn.fish_result_image
531 (fish_result_id, image_id) VALUES (?, ?)";
532 my $sth = $self->get_dbh()->prepare($query);
533 $sth->execute($fish_result_id, $self->get_image_id());
534 my $id= $self->get_currval("sgn.fish_result_image_fish_result_image_id_seq");
538 =head2 get_fish_result_clone_ids
540 Usage: my @clone_ids = $image->get_fish_result_clones();
541 Desc: because fish results are associated with genomic
542 clones, this function returns the genomic clone ids
543 that are associated through the fish results to
544 this image. The clone ids can be used to construct
545 links to the BAC detail page.
546 Ret: A list of clone_ids
553 sub get_fish_result_clone_ids
{
555 my $query = "SELECT distinct(clone_id) FROM sgn.fish_result_image join sgn.fish_result using(fish_result_id) WHERE fish_result_image.image_id=?";
556 my $sth = $self->get_dbh()->prepare($query);
557 $sth->execute($self->get_image_id());
558 my @fish_result_clone_ids = ();
559 while (my ($fish_result_clone_id) = $sth->fetchrow_array()) {
560 push @fish_result_clone_ids, $fish_result_clone_id;
562 return @fish_result_clone_ids;
565 =head2 get_associated_objects
575 sub get_associated_objects
{
577 my @associations = ();
578 my @stocks=$self->get_stocks();
579 foreach my $stock (@stocks) {
580 my $stock_id = $stock->stock_id();
581 my $stock_name = $stock->name();
582 push @associations, [ "stock", $stock_id, $stock_name ];
585 foreach my $exp ($self->get_experiments()) {
586 my $experiment_id = $exp->get_experiment_id();
587 my $experiment_name = $exp->get_name();
589 push @associations, [ "experiment", $experiment_id, $experiment_name ];
591 #print "<a href=\"/insitu/detail/experiment.pl?experiment_id=$experiment_id&action=view\">".($exp->get_name())."</a>";
594 foreach my $fish_result_clone_id ($self->get_fish_result_clone_ids()) {
595 push @associations, [ "fished_clone", $fish_result_clone_id ];
597 foreach my $locus ($self->get_loci() ) {
598 push @associations, ["locus", $locus->get_locus_id(), $locus->get_locus_name];
600 foreach my $o ($self->get_organisms ) {
601 push @associations, ["organism", $o->organism_id, $o->species];
604 foreach my $cvterm ( $self->get_cvterms ) {
605 push @associations, ["cvterm" , $cvterm->cvterm_id, $cvterm->name];
607 return @associations;
610 =head2 associate_locus
612 Usage: $image->associate_locus($locus_id)
613 Desc: associate a locus with this image
621 sub associate_locus
{
623 my $locus_id = shift;
624 my $sp_person_id= $self->get_sp_person_id();
625 my $query = "INSERT INTO phenome.locus_image
630 my $sth = $self->get_dbh()->prepare($query);
634 $self->get_image_id()
637 my $locus_image_id= $self->get_currval("phenome.locus_image_locus_image_id_seq");
638 return $locus_image_id;
644 Usage: $self->get_loci
645 Desc: find the locus objects asociated with this image
646 Ret: a list of locus objects
655 my $query = "SELECT locus_id FROM phenome.locus_image WHERE locus_image.obsolete = 'f' and locus_image.image_id=?";
656 my $sth = $self->get_dbh()->prepare($query);
657 $sth->execute($self->get_image_id());
660 while (my ($locus_id) = $sth->fetchrow_array()) {
661 $locus = CXGN
::Phenome
::Locus
->new($self->get_dbh(), $locus_id);
668 =head2 associate_organism
670 Usage: $image->associate_organism($organism_id)
679 sub associate_organism
{
681 my $organism_id = shift;
682 my $sp_person_id= $self->get_sp_person_id();
683 my $query = "INSERT INTO metadata.md_image_organism
687 VALUES (?, ?, ?) RETURNING md_image_organism_id";
688 my $sth = $self->get_dbh()->prepare($query);
694 my ($image_organism_id) = $sth->fetchrow_array;
695 return $image_organism_id;
700 Usage: $self->get_organisms
701 Desc: find the organism objects asociated with this image
702 Ret: a list of BCS Organism objects
711 my $schema = $self->config->dbic_schema('Bio::Chado::Schema' , 'sgn_chado');
712 my $query = "SELECT organism_id FROM metadata.md_image_organism WHERE md_image_organism.obsolete != 't' and md_image_organism.image_id=?";
713 my $sth = $self->get_dbh()->prepare($query);
714 $sth->execute($self->get_image_id());
716 while (my ($o_id) = $sth->fetchrow_array ) {
717 push @organisms, $schema->resultset("Organism::Organism")->find(
718 { organism_id
=> $o_id } );
724 =head2 get_associated_object_links
730 Description: gets the associated objects as links in tabular format
734 sub get_associated_object_links
{
737 foreach my $assoc ($self->get_associated_objects()) {
739 if ($assoc->[0] eq "stock") {
740 $s .= "<a href=\"/stock/$assoc->[1]/view\">Stock name: $assoc->[2].</a>";
743 if ($assoc->[0] eq "experiment") {
744 $s .= "<a href=\"/insitu/detail/experiment.pl?experiment_id=$assoc->[1]&action=view\">insitu experiment $assoc->[2]</a>";
747 if ($assoc->[0] eq "fished_clone") {
748 $s .= qq { <a href
="/maps/physical/clone_info.pl?id=$assoc->[1]">FISHed clone id
:$assoc->[1]</a
> };
750 if ($assoc->[0] eq "locus" ) {
751 $s .= qq { <a href
="/phenome/locus_display.pl?locus_id=$assoc->[1]">Locus name
:$assoc->[2]</a
> };
753 if ($assoc->[0] eq "organism" ) {
754 $s .= qq { <a href
="/organism/$assoc->[1]/view/">Organism name
:$assoc->[2]</a
> };
756 if ($assoc->[0] eq "cvterm" ) {
757 $s .= qq { <a href
="/cvterm/$assoc->[1]/view/">Cvterm
: $assoc->[2]</a
> };
764 =head2 associate_cvterm
766 Usage: $image->associate_cvterm($cvterm_id)
767 Desc: link uploaded image with a cvterm
768 Ret: database ID md_image_cvterm_id
770 Side Effects: Insert database row
775 sub associate_cvterm
{
777 my $cvterm_id = shift;
778 my $sp_person_id= $self->get_sp_person_id();
779 my $query = "INSERT INTO metadata.md_image_cvterm
783 VALUES (?, ?, ?) RETURNING md_image_cvterm_id";
784 my $sth = $self->get_dbh()->prepare($query);
790 my ($image_cvterm_id) = $sth->fetchrow_array;
791 return $image_cvterm_id;
796 Usage: $self->get_cvterms
797 Desc: find the cvterm objects asociated with this image
798 Ret: a list of BCS Cvterm objects
807 my $schema = $self->config->dbic_schema('Bio::Chado::Schema' , 'sgn_chado');
808 my $query = "SELECT cvterm_id FROM metadata.md_image_cvterm WHERE md_image_cvterm.obsolete != 't' and md_image_cvterm.image_id=?";
809 my $sth = $self->get_dbh()->prepare($query);
810 $sth->execute( $self->get_image_id() );
812 while (my ($cvterm_id) = $sth->fetchrow_array ) {
813 push @cvterms, $schema->resultset("Cv::Cvterm")->find(
814 { cvterm_id
=> $cvterm_id } );