Merge pull request #5191 from solgenomics/topic/quality_control
[sgn.git] / lib / CXGN / BrAPI / v2 / Images.pm
blob3e11197f998472a922f906bea78c88cdcadd68b8
1 package CXGN::BrAPI::v2::Images;
3 use Moose;
4 use Data::Dumper;
5 use File::Basename;
6 use File::Slurp qw | slurp |;
7 use Image::Size;
8 use SGN::Model::Cvterm;
9 use SGN::Image;
10 use CXGN::Image::Search;
11 use CXGN::Page;
12 use CXGN::Tag;
13 use CXGN::Phenotypes::StorePhenotypes;
14 use Scalar::Util qw(looks_like_number);
16 extends 'CXGN::BrAPI::v2::Common';
18 sub search {
19 my $self = shift;
20 my $params = shift;
21 my $page_size = $self->page_size;
22 my $page = $self->page;
23 my $status = $self->status;
24 my $page_obj = CXGN::Page->new();
25 my $hostname = $page_obj->get_hostname();
26 my @data_files;
28 my $image_ids_arrayref = $params->{imageDbId} || ($params->{imageDbIds} || ());
29 my $image_names_arrayref = $params->{imageName} || ($params->{imageNames} || ());
30 my $stock_ids_arrayref = $params->{observationUnitDbId} || ($params->{observationUnitDbIds} || ());
31 my $phenotype_ids_arrayref = $params->{observationDbId} || ($params->{observationDbIds} || ());
32 my $descriptors_arrayref = $params->{descriptiveOntologyTerm} || ($params->{descriptiveOntologyTerms} || ());
33 my $reference_ids_arrayref = $params->{externalReferenceId} || ($params->{externalReferenceIds} || ());
34 my $reference_sources_arrayref = $params->{externalReferenceSource} || ($params->{externalReferenceSources} || ());
35 my $imagefile_names_arrayref = $params->{imageFileNames} || ($params->{imageFileNames} || ());
36 my $imagefile_size_max = $params->{imageFileSizeMax}->[0] || undef;
37 my $imagefile_size_min = $params->{imageFileSizeMin}->[0] || undef;
38 my $image_height_max = $params->{imageHeightMax}->[0] || undef;
39 my $image_height_min = $params->{imageHeightMin}->[0] || undef;
40 my $image_location_arrayref = $params->{imageLocation} || ($params->{imageLocation} || ());
41 my $image_timestamp_end = $params->{imageTimeStampRangeEnd}->[0] || undef;
42 my $image_timestamp_start = $params->{imageTimeStampRangeStart}->[0] || undef;
43 my $image_width_max = $params->{imageWidthMax}->[0] || undef;
44 my $image_width_min = $params->{imageWidthMin}->[0] || undef;
45 my $mimetypes_arrayref = $params->{mimeTypes } || ($params->{mimeTypes} || ());
47 if (($phenotype_ids_arrayref && scalar(@$phenotype_ids_arrayref)>0) || ($reference_ids_arrayref && scalar(@$reference_ids_arrayref)>0) || ($reference_sources_arrayref && scalar(@$reference_sources_arrayref)>0) || ($image_location_arrayref && scalar(@$image_location_arrayref)>0)){
48 push @$status, { 'error' => 'The following search parameters are not implemented: observationDbId, externalReferenceID, externalReferenceSources, imageLocation' };
51 my %imagefile_names_arrayref;
52 if ($imagefile_names_arrayref && scalar(@$imagefile_names_arrayref)>0){
53 %imagefile_names_arrayref = map { $_ => 1} @$imagefile_names_arrayref;
56 my %phenotype_ids_arrayref;
57 if ($phenotype_ids_arrayref && scalar(@$phenotype_ids_arrayref)>0){
58 %phenotype_ids_arrayref = map { $_ => 1} @$phenotype_ids_arrayref;
61 my %mimetypes_arrayref;
62 if ($mimetypes_arrayref && scalar(@$mimetypes_arrayref)>0){
63 %mimetypes_arrayref = map { $_ => 1} @$mimetypes_arrayref;
66 my $start_index = $page*$page_size;
67 my $end_index = $page*$page_size + $page_size;
69 my $limit = $end_index-$start_index;
70 my $offset = $start_index;
72 my $image_search = CXGN::Image::Search->new({
73 bcs_schema=>$self->bcs_schema(),
74 people_schema=>$self->people_schema(),
75 phenome_schema=>$self->phenome_schema(),
76 image_name_list=>$image_names_arrayref,
77 description_list=>$descriptors_arrayref,
78 stock_id_list=>$stock_ids_arrayref,
79 image_id_list=>$image_ids_arrayref,
80 # still need to implement in the search
81 # phenotype_id_list=>$phenotype_ids_arrayref,
82 # imagefile_names_list =>$imagefile_names_arrayref,
83 # image_location_list =>$image_location_arrayref,
84 # mimetypes_list =>$mimetypes_arrayref
85 limit=>$limit,
86 offset=>$offset
87 });
88 my ($result, $total_count) = $image_search->search();
90 my @data;
91 my $start_index = $page*$page_size;
92 my $end_index = $page*$page_size + $page_size - 1;
93 my $counter = 0;
95 foreach (@$result) {
96 my $mimetype = _get_mimetype($_->{'image_file_ext'});
97 if ( (%mimetypes_arrayref && !exists($mimetypes_arrayref{$mimetype}))) { next; }
98 if ( (%imagefile_names_arrayref && !exists($imagefile_names_arrayref{$_->{'image_original_filename'}}))) { next; }
99 if ( $image_timestamp_start && _to_comparable($_->{'image_modified_date'}) lt _to_comparable($image_timestamp_start) ) { next; }
100 if ( $image_timestamp_end && _to_comparable($_->{'image_modified_date'}) gt _to_comparable($image_timestamp_end) ) { next; }
102 my $image = SGN::Image->new($self->bcs_schema()->storage->dbh(), $_->{'image_id'});
103 my @cvterms = $image->get_cvterms();
104 my $url = $hostname . $image->get_image_url('medium');
105 my $filename = $image->get_filename();
106 my $size = (stat($filename))[7];
107 my ($width, $height) = imgsize($filename);
109 if ( $imagefile_size_max && $size > $imagefile_size_max ) { next; }
110 if ( $imagefile_size_min && $size < $imagefile_size_min + 1 ) { next; }
111 if ( $image_height_max && $height > $image_height_max ) { next; }
112 if ( $image_height_min && $height < $image_height_min + 1 ) { next; }
113 if ( $image_width_max && $width > $image_width_max ) { next; }
114 if ( $image_width_min && $width < $image_width_min + 1 ) { next; }
116 # Process cvterms
117 my @cvterm_names;
118 foreach (@cvterms) {
119 push(@cvterm_names, $_->name);
122 # Get the observation db ids
123 my @observationDbIds;
124 my $observations_array = $_->{'observations_array'};
126 foreach (@$observations_array) {
127 my $observationDbId = $_->{'phenotype_id'};
128 push @observationDbIds, $observationDbId
131 my %unique_tags;
132 foreach (@{$_->{'tags_array'}}) {
133 $unique_tags{$_->{tag_id}} = $_;
135 my @sorted_tags;
136 foreach my $tag_id (sort keys %unique_tags) {
137 push @sorted_tags, $unique_tags{$tag_id}{name};
140 if ($counter >= $start_index && $counter <= $end_index) {
141 push @data, {
142 additionalInfo => {
143 observationLevel => $_->{'stock_type_name'},
144 observationUnitName => $_->{'stock_uniquename'},
145 tags => \@sorted_tags,
147 copyright => $_->{'image_username'} . " " . substr($_->{'image_modified_date'}, 0, 4),
148 description => $_->{'image_description'},
149 descriptiveOntologyTerms => \@cvterm_names,
150 externalReferences => [],
151 imageDbId => qq|$_->{'image_id'}|,
152 imageFileName => $_->{'image_original_filename'},
153 imageFileSize => $size,
154 imageHeight => $height,
155 imageWidth => $width,
156 imageName => $_->{'image_name'},
157 imageTimeStamp => $_->{'image_modified_date'},
158 imageURL => $url,
159 mimeType => _get_mimetype($_->{'image_file_ext'}),
160 observationUnitDbId => qq|$_->{'stock_id'}|,
161 # location and linked phenotypes are not yet available for images in the db
162 imageLocation => undef,
163 observationDbIds => [ @observationDbIds ],
166 $counter++;
169 my %result = (data => \@data);
171 my $pagination = CXGN::BrAPI::Pagination->pagination_response($total_count,$page_size,$page);
172 return CXGN::BrAPI::JSONResponse->return_success(\%result, $pagination, \@data_files, $status, 'Image search result constructed');
175 sub detail {
176 my $self = shift;
177 my $inputs = shift;
178 my $page_size = $self->page_size;
179 my $page = $self->page;
180 my $status = $self->status;
181 my $page_obj = CXGN::Page->new();
182 my $hostname = $page_obj->get_hostname();
183 my @data_files;
185 my $image = SGN::Image->new($self->bcs_schema()->storage->dbh(), $inputs->{image_id});
186 my @cvterms = $image->get_cvterms();
187 my $url = $hostname . $image->get_image_url('medium');
188 my $filename = $image->get_filename();
189 my $size = (stat($filename))[7];
190 my ($width, $height) = imgsize($filename);
192 my @image_ids;
193 push @image_ids, $inputs->{image_id};
194 my $image_search = CXGN::Image::Search->new({
195 bcs_schema=>$self->bcs_schema(),
196 people_schema=>$self->people_schema(),
197 phenome_schema=>$self->phenome_schema(),
198 image_id_list=>\@image_ids
201 my ($search_result, $total_count) = $image_search->search();
202 my %result;
204 foreach (@$search_result) {
206 # Process cvterms
207 my @cvterm_names;
208 foreach (@cvterms) {
209 push(@cvterm_names, $_->name);
212 # Get the observation variable db ids
213 my @observationDbIds;
214 my $observations_array = $_->{'observations_array'};
216 foreach (@$observations_array) {
217 my $observationDbId = $_->{'phenotype_id'};
218 push @observationDbIds, $observationDbId
221 my %unique_tags;
222 foreach (@{$_->{'tags_array'}}) {
223 $unique_tags{$_->{tag_id}} = $_;
225 my @sorted_tags;
226 foreach my $tag_id (sort keys %unique_tags) {
227 push @sorted_tags, $unique_tags{$tag_id}{name};
230 %result = (
231 additionalInfo => {
232 observationLevel => $_->{'stock_type_name'},
233 observationUnitName => $_->{'stock_uniquename'},
234 tags => \@sorted_tags,
236 copyright => $_->{'image_username'} . " " . substr($_->{'image_modified_date'},0,4),
237 description => $_->{'image_description'},
238 descriptiveOntologyTerms => \@cvterm_names,
239 externalReferences => [],
240 imageDbId => qq|$_->{'image_id'}|,
241 imageFileName => $_->{'image_original_filename'},
242 imageFileSize => $size,
243 imageHeight => $height,
244 imageWidth => $width,
245 imageName => $_->{'image_name'},
246 imageTimeStamp => $_->{'image_modified_date'},
247 imageURL => $url,
248 mimeType => _get_mimetype($_->{'image_file_ext'}),
249 observationUnitDbId => qq|$_->{'stock_id'}|,
250 # location and linked phenotypes are not yet available for images in the db
251 imageLocation => undef,
252 observationDbIds => [@observationDbIds],
256 my $total_count = 1;
257 my $pagination = CXGN::BrAPI::Pagination->pagination_response($total_count,$page_size,$page);
258 return CXGN::BrAPI::JSONResponse->return_success(\%result, $pagination, \@data_files, $status, 'Image detail constructed');
261 sub image_metadata_store {
262 my $self = shift;
263 my $data = shift;
264 my $image_dir = shift;
265 my $user_id = shift;
266 my $user_type = shift;
267 my $image_id = shift;
269 my $page_size = $self->page_size;
270 my $page = $self->page;
271 my $status = $self->status;
272 my $dbh = $self->bcs_schema()->storage()->dbh();
273 my $page_obj = CXGN::Page->new();
274 my $hostname = $page_obj->get_hostname();
275 my @image_ids;
277 foreach my $params (@{$data}) {
278 my $image_id = $params->{imageDbId} ? $params->{imageDbId} : undef;
279 my $imageName = $params->{imageName} ? $params->{imageName} : "";
280 my $description = $params->{description} ? $params->{description} : "";
281 my $imageFileName = $params->{imageFileName} ? $params->{imageFileName} : "";
282 print STDERR "Image filename in metadata store is: $imageFileName\n";
283 my $mimeType = $params->{mimeType} ? $params->{mimeType} : undef;
284 my $observationUnitDbId = $params->{observationUnitDbId} ? $params->{observationUnitDbId} : undef;
285 my $descriptiveOntologyTerms_arrayref = $params->{descriptiveOntologyTerms} || ();
286 my $observationDbIds_arrayref = $params->{observationDbIds} || ();
288 # metadata store for the rest not yet implemented
289 my $imageFileSize = $params->{imageFileSize} ? $params->{imageFileSize} : undef;
290 my $imageHeight = $params->{imageHeight} ? $params->{imageHeight} : ();
291 my $imageWidth = $params->{imageWidth} ? $params->{imageWidth} : ();
292 my $copyright = $params->{copyright} || "";
293 my $imageTimeStamp = $params->{imageTimeStamp} || "";
294 my $imageLocation_hashref = $params->{imageLocation} || ();
295 my $additionalInfo_hashref = $params->{additionalInfo} || ();
297 # Prechecks before storing
298 # Check that our observation unit db id exists. If not return error.
299 if ($observationUnitDbId) {
300 my $stock = $self->bcs_schema()->resultset("Stock::Stock")->find({ stock_id => $observationUnitDbId });
301 if (! defined $stock) {
302 return CXGN::BrAPI::JSONResponse->return_error($self->status, 'Stock id is not valid. Cannot generate image metadata');
306 # Check that the cvterms are valid before continuing
307 my @cvterm_ids;
308 foreach (@$descriptiveOntologyTerms_arrayref) {
309 my $cvterm_id;
310 # If is like number, search for id
311 if (looks_like_number($_)) {
312 # Check if the trait exists
313 $cvterm_id = SGN::Model::Cvterm->find_trait_by_id($self->bcs_schema(), $_);
315 else {
316 # else search for string
317 $cvterm_id = SGN::Model::Cvterm->find_trait_by_name($self->bcs_schema(), $_);
320 if (!defined $cvterm_id) {
321 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Descriptive ontology term %s not found. Cannot generate image metadata', $_));
324 push(@cvterm_ids, $cvterm_id);
327 # Check that the image type they want to pass in is supported.
328 # If it is not converted, and is the same after _get_extension, it is not supported.
329 my $extension_type = _get_extension($mimeType);
330 if ($extension_type eq $mimeType) {
331 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Mime type %s is not supported.', $mimeType));
334 # Check if an image id was passed in, and if that image exists
335 my $image_obj = CXGN::Image->new( dbh=>$dbh, image_dir => $image_dir, image_id => $image_id);
336 if ($image_id && ! defined $image_obj->get_create_date()) {
337 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Image with id of %s, does not exist', $image_id));
340 # Check that the observationDbIds they passed exists
341 foreach (@$observationDbIds_arrayref) {
342 my $phenotype = $self->bcs_schema()->resultset("Phenotype::Phenotype")->find({ phenotype_id => $_ });
343 if (! defined $phenotype) {
344 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Observation with id of %s, does not exist', $_));
349 # End of prechecks
351 # Assign image properties
352 unless ($image_id) { $image_obj->set_sp_person_id($user_id); }
353 $image_obj->set_name($imageName);
354 $image_obj->set_description($description);
355 $image_obj->set_original_filename($imageFileName);
356 $image_obj->set_file_ext($extension_type);
358 # Save the image to the db
359 $image_id = $image_obj->store();
361 my $image = SGN::Image->new($self->bcs_schema()->storage->dbh(), $image_id);
363 # Remove cvterms so we can reassign them later
364 my @prev_cvterms = $image->get_cvterms();
365 foreach (@prev_cvterms) {
366 $image->remove_associated_cvterm($_->cvterm_id);
369 # Store desceriptiveOntologyTerms in the cvterm after finding the cvterm here.
370 foreach (@cvterm_ids) {
371 $image->associate_cvterm($_);
374 # Clear previously associated stocks.
375 my @stocks = $image->get_stocks();
376 foreach(@stocks){
377 $image->remove_stock($_->stock_id);
380 # Associate our stock with the image, if a stock_id was provided.
381 if ($observationUnitDbId) {
382 my $person = CXGN::People::Person->new($dbh, $user_id);
383 my $user_name = $person->get_username;
384 $image->associate_stock($observationUnitDbId, $user_name);
387 # Clear previously associated phenotypes
388 $image->remove_associated_phenotypes();
390 # Associate the image with the observations specified
391 foreach (@$observationDbIds_arrayref) {
393 my $nd_experiment_phenotype = $self->bcs_schema()->resultset("NaturalDiversity::NdExperimentPhenotype")->find({ phenotype_id => $_ });
395 if ($nd_experiment_phenotype) {
396 my %image_hash = ($nd_experiment_phenotype->nd_experiment_id => $image_id);
397 $image->associate_phenotype(\%image_hash);
398 } else {
399 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Cannot find experiment associated with observation with id of %s, does not exist', $_));
403 if ($additionalInfo_hashref) {
404 my $tag_list = $additionalInfo_hashref->{tags};
405 if($tag_list && scalar(@$tag_list) > 0){
406 foreach(@$tag_list){
407 my $image_tag_id = CXGN::Tag::exists_tag_named($self->bcs_schema()->storage->dbh, $_);
409 if (!$image_tag_id) {
410 my $image_tag = CXGN::Tag->new($self->bcs_schema()->storage->dbh);
411 $image_tag->set_name($_);
412 $image_tag->set_description('Image: '.$_);
413 $image_tag->set_sp_person_id($user_id);
414 $image_tag_id = $image_tag->store();
416 my $image_tag = CXGN::Tag->new($self->bcs_schema()->storage->dbh, $image_tag_id);
419 $image->add_tag($image_tag);
424 push @image_ids, $image_id;
427 my $image_search = CXGN::Image::Search->new({
428 bcs_schema=>$self->bcs_schema(),
429 people_schema=>$self->people_schema(),
430 phenome_schema=>$self->phenome_schema(),
431 image_id_list=>\@image_ids
434 my ($result, $total_count) = $image_search->search();
436 my @data;
437 my $counter = 0;
439 foreach (@$result) {
440 my $mimetype = _get_mimetype($_->{'image_file_ext'});
441 my $image = SGN::Image->new($self->bcs_schema()->storage->dbh(), $_->{'image_id'});
442 my @cvterms = $image->get_cvterms();
444 # my $url = $hostname . $image->get_image_url('medium');
445 # my $filename = $image->get_filename();
446 # my $size = (stat($filename))[7];
447 # my ($width, $height) = imgsize($filename);
449 # Process cvterms
450 my @cvterm_names;
451 foreach (@cvterms) {
452 push(@cvterm_names, $_->name);
455 # Get the observation db ids
456 my @observationDbIds;
457 my $observations_array = $_->{'observations_array'};
459 foreach (@$observations_array) {
460 my $observationDbId = $_->{'phenotype_id'};
461 push @observationDbIds, $observationDbId
464 my %unique_tags;
465 foreach (@{$_->{'tags_array'}}) {
466 $unique_tags{$_->{tag_id}} = $_;
468 my @sorted_tags;
469 foreach my $tag_id (sort keys %unique_tags) {
470 push @sorted_tags, $unique_tags{$tag_id}{name};
473 push @data, {
474 additionalInfo => {
475 observationLevel => $_->{'stock_type_name'},
476 observationUnitName => $_->{'stock_uniquename'},
477 tags => \@sorted_tags,
479 copyright => $_->{'image_username'} . " " . substr($_->{'image_modified_date'},0,4),
480 description => $_->{'image_description'},
481 descriptiveOntologyTerms => \@cvterm_names,
482 externalReferences => [],
483 imageDbId => qq|$_->{'image_id'}|,
484 imageFileName => $_->{'image_original_filename'},
485 # imageFileSize => $size,
486 # imageHeight => $height,
487 # imageWidth => $width,
488 imageName => $_->{'image_name'},
489 imageTimeStamp => $_->{'image_modified_date'},
490 # imageURL => $url,
491 mimeType => _get_mimetype($_->{'image_file_ext'}),
492 observationUnitDbId => qq|$_->{'stock_id'}|,
493 # location and linked phenotypes are not yet available for images in the db
494 imageLocation => undef,
495 observationDbIds => [@observationDbIds],
498 $counter++;
501 my $result;
502 if ($image_id) {
503 $result = $data[0];
504 } else {
505 $result = {data => \@data};
508 my $pagination = CXGN::BrAPI::Pagination->pagination_response($counter,$page_size,$page);
509 return CXGN::BrAPI::JSONResponse->return_success( $result, $pagination, undef, $self->status(), 'Image metadata stored');
512 sub image_data_store {
513 my $self = shift;
514 my $image_dir = shift;
515 my $image_id = shift;
516 my $inputs = shift;
517 my $content_type = shift;
519 print STDERR "Image ID: $image_id. inputs to image metadata store: ".Dumper($inputs);
521 # Get our image file extension type from the database
522 my @image_ids;
523 push @image_ids, $image_id;
524 my $image_search = CXGN::Image::Search->new({
525 bcs_schema=>$self->bcs_schema(),
526 people_schema=>$self->people_schema(),
527 phenome_schema=>$self->phenome_schema(),
528 image_id_list=>\@image_ids
531 my ($search_result, $total_count) = $image_search->search();
532 my $file_extension = @$search_result[0]->{'image_file_ext'};
533 my $original_filename = @$search_result[0]->{'image_original_filename'};
535 if (! defined $file_extension) {
536 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Unsupported image type, %s', $file_extension));
539 my $tempfile = $inputs->filename();
540 my ($filename, $tempdir, $extension) = fileparse($tempfile);
542 my $updated_tempfile_name = $tempdir . $original_filename;
544 print STDERR "\n\n Updated tempfile name is $updated_tempfile_name\n";
546 rename($tempfile, $updated_tempfile_name);
548 # process image data through CXGN::Image...
550 my $cxgn_img = CXGN::Image->new(dbh=>$self->bcs_schema()->storage()->dbh(), image_dir => $image_dir, image_id => $image_id);
552 eval {
553 $cxgn_img->process_image($updated_tempfile_name);
556 if ($@) {
557 print STDERR "An error occurred during image processing... $@\n";
559 else {
560 print STDERR "Image processed successfully.\n";
563 my %result = ( image_id => $image_id);
565 foreach (@$search_result) {
566 my $sgn_image = SGN::Image->new($self->bcs_schema()->storage->dbh(), $_->{'image_id'});
567 my $page_obj = CXGN::Page->new();
568 my $hostname = $page_obj->get_hostname();
569 my $url = $hostname . $sgn_image->get_image_url('medium');
570 my $filename = $sgn_image->get_filename();
571 my $size = (stat($filename))[7];
572 my ($width, $height) = imgsize($filename);
574 # Get the observation variable db ids
575 my @observationDbIds;
576 my $observations_array = $_->{'observations_array'};
578 foreach (@$observations_array) {
579 my $observationDbId = $_->{'phenotype_id'};
580 push @observationDbIds, $observationDbId
583 my %unique_tags;
584 foreach (@{$_->{'tags_array'}}) {
585 $unique_tags{$_->{tag_id}} = $_;
587 my @sorted_tags;
588 foreach my $tag_id (sort keys %unique_tags) {
589 push @sorted_tags, $unique_tags{$tag_id}{name};
592 my @cvterms = $sgn_image->get_cvterms();
593 # Process cvterms
594 my @cvterm_names;
595 foreach (@cvterms) {
596 push(@cvterm_names, $_->name);
599 %result = (
600 additionalInfo => {
601 observationLevel => $_->{'stock_type_name'},
602 observationUnitName => $_->{'stock_uniquename'},
603 tags => \@sorted_tags,
605 copyright => $_->{'image_username'} . " " . substr($_->{'image_modified_date'},0,4),
606 description => $_->{'image_description'},
607 descriptiveOntologyTerms => \@cvterm_names,
608 externalReferences => [],
609 imageDbId => $_->{'image_id'},
610 imageFileName => $_->{'image_original_filename'},
611 imageFileSize => $size,
612 imageHeight => $height,
613 imageWidth => $width,
614 imageName => $_->{'image_name'},
615 imageTimeStamp => $_->{'image_modified_date'},
616 imageURL => $url,
617 mimeType => _get_mimetype($_->{'image_file_ext'}),
618 observationUnitDbId => $_->{'stock_id'},
619 # location and linked phenotypes are not yet available for images in the db
620 imageLocation => undef,
621 observationDbIds => [@observationDbIds],
625 my $pagination = CXGN::BrAPI::Pagination->pagination_response(1, 10, 0);
626 return CXGN::BrAPI::JSONResponse->return_success( \%result, $pagination, [], $self->status(), 'Image data store successful');
629 sub _get_mimetype {
630 my $extension = shift || '';
631 my %mimetypes = (
632 '.jpg' => 'image/jpeg',
633 '.JPG' => 'image/jpeg',
634 '.jpeg' => 'image/jpeg',
635 '.png' => 'image/png',
636 '.gif' => 'image/gif',
637 '.svg' => 'image/svg+xml',
638 '.pdf' => 'application/pdf',
639 '.ps' => 'application/postscript',
641 if ( defined $mimetypes{$extension} ) {
642 return $mimetypes{$extension};
643 } else {
644 return $extension;
648 sub _get_extension {
649 my $mimetype = shift;
650 my %extensions = (
651 'image/jpeg' => '.jpg',
652 'image/png' => '.png',
653 'image/gif' => '.gif',
654 'image/svg+xml' => '.svg',
655 'application/pdf' => '.pdf',
656 'application/postscript' => '.ps'
658 if ( defined $extensions{$mimetype} ) {
659 return $extensions{$mimetype};
660 } else {
661 return $mimetype;
665 sub _to_comparable {
667 my $str_date = shift;
668 my $date;
669 if ($str_date) {
670 $str_date =~ s/\ /+/g; #clean_inputs delete +, adding it
671 my $formatted_time = Time::Piece->strptime($str_date,'%Y-%m-%dT%T %z');
672 $date = $formatted_time->epoch;
675 return $date;