At this time this is NOT an Image Field service - it is a service that exposes all variations of an Image node's images (including ones created by ImageCache) when given the node id of a valid Image node provided by the Image module.

I will not be making an Image Field service any time soon, so if you want one, either make it yourself or extend this module so it supports CCK Image Field. Either way, don't bother asking in this thread for such a feature, as it won't be built. Sorry, but I don't have the time.

Now for the module:

/**
* Implementation of hook_perm().
*/
function image_service_perm() {
  return array('get image files');
}

/**
 * Implementation of hook_service().
 */
function image_service_service() {
  return array(
    array(
      '#method'   => 'image.getImages',
      '#callback' => 'image_service_get_images',
      '#access callback' => 'image_service_get_images_access',
      '#args'     => array(
        array(
          '#name'         => 'nid',
          '#type'         => 'int',
          '#description'  => t('A node id.'),
        ),
      ),
      '#return'   => 'struct',
      '#help'     => t('Returns the images attached to a node.')
    ),
  );
}

/**
 * when given a node id returns any image data and images
 * assigned to that node
 * 
 * @param $nid
 * integer representing the nid of either an image or a node with
 * attached images
 * 
 * @return
 * array containing images by size for this node
 */
function image_service_get_images($nid) {
  if (module_exists('image')) {
    $image_node = node_load($nid);
    if ($image_node->type == 'image') {
      foreach($image_node->images as $type => $path) {
      	$fid = db_result(db_query("SELECT fid FROM {image} WHERE nid = %d AND image_size = '%s'", $nid, $type));
        $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE fid = %d AND filename = '%s'", $fid, $type));
        $fullpath = $_SERVER['DOCUMENT_ROOT'] . base_path();
        $binaryfile = fopen($fullpath, 'rb');
        $send[$type]['file'] = base64_encode(fread($binaryfile, filesize($fullpath)));
        $send[$type]['filename'] = $file->filename;
        $send[$type]['uid'] = $file->uid;
        $send[$type]['filemime'] = $file->filemime;
        $send[$type]['filesize'] = $file->filesize;
        $send[$type]['status'] = $file->status;
        $send[$type]['timestamp'] = $file->timestamp;
        preg_match_all('/.*\/images\/(.*)/', $path, $matches);
        $send[$type]['fullname'] = $matches[1][0];
        fclose($binaryfile);
      }
      return $send;
    } else {
      return array(0 => 'node was not of type image');
    }
  } else {
    return array(0 => 'image module not enabled on remote service provider');
  }
}

/**
* access callback function for the image service
*/
function image_service_get_images_access() {
  return user_access('get image files');
}

Comments

greg.harvey’s picture

Arg, I *hate* that you can't edit the first post in an Issue! To re-iterate:

At this time this is NOT an Image Field service - it is a service that exposes all variations of an Image node's images (including ones created by ImageCache) when given the node id of a valid Image node provided by the Image module.

Anyway, I re-wrote it slightly in the form here on Drupal.org (stupid idea) and made a slight mistake - please disregard the first post and use this:

/**
* Implementation of hook_perm().
*/
function image_service_perm() {
  return array('get image files');
}

/**
* Implementation of hook_service().
*/
function image_service_service() {
  return array(
    array(
      '#method'   => 'image.getImages',
      '#callback' => 'image_service_get_images',
      '#access callback' => 'image_service_get_images_access',
      '#args'     => array(
        array(
          '#name'         => 'nid',
          '#type'         => 'int',
          '#description'  => t('A node id.'),
        ),
      ),
      '#return'   => 'struct',
      '#help'     => t('Returns the images attached to a node.')
    ),
  );
}

/**
* when given a node id returns any image data and images
* assigned to that node
*
* @param $nid
* integer representing the nid of either an image or a node with
* attached images
*
* @return
* array containing images by size for this node
*/
function image_service_get_images($nid) {
  if (module_exists('image')) {
    $image_node = node_load($nid);
    if ($image_node->type == 'image') {
      foreach($image_node->images as $type => $path) {
        $fid = db_result(db_query("SELECT fid FROM {image} WHERE nid = %d AND image_size = '%s'", $nid, $type));
        $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE fid = %d AND filename = '%s'", $fid, $type));
        $fullpath = $_SERVER['DOCUMENT_ROOT'] . base_path() . $path;
        $binaryfile = fopen($fullpath, 'rb');
        $send[$type]['file'] = base64_encode(fread($binaryfile, filesize($fullpath)));
        $send[$type]['filename'] = $file->filename;
        $send[$type]['uid'] = $file->uid;
        $send[$type]['filemime'] = $file->filemime;
        $send[$type]['filesize'] = $file->filesize;
        $send[$type]['status'] = $file->status;
        $send[$type]['timestamp'] = $file->timestamp;
        preg_match_all('/.*\/images\/(.*)/', $path, $matches);
        $send[$type]['fullname'] = $matches[1][0];
        fclose($binaryfile);
      }
      return $send;
    } else {
      return array(0 => 'node was not of type image');
    }
  } else {
    return array(0 => 'image module not enabled on remote service provider');
  }
}

/**
* access callback function for the image service
*/
function image_service_get_images_access() {
  return user_access('get image files');
}
greg.harvey’s picture

Ps - I note from looking at the changes made to my file service before it was committed that there are better ways to do things in the above code. If you like, I can update this and attach files to properly reflect the correct structure for a new service module. But it might take me a few weeks to find a hole in my schedule to do it. The above code will work, but the approach used in the file_service module in 6.x-0.13 is more elegant. If anyone wants to refactor this before I get a chance to, feel free! =)

greg.harvey’s picture

Actually, it occurs to me that since the Image module is not core, this service ought really to be part of the Image module package, not the Services module package. Thoughts? If the maintainers of Services agree, please feel free to switch this to the latest 6.x dev version of Image instead. =)

darrenmothersele’s picture

Thanks for posting this, Greg.

I'll have a shot at implementing an ImageField service.

marcingy’s picture

Status: Needs review » Closed (won't fix)

Greg

You are correct this really doesn't belong in the services package (I know we have views in there but it is a sort of special exception).

I'm going to mark this as won't fix and either you can look to get it into image or maybe create a new project for this.

Marc

greg.harvey’s picture

Hi Marc,

I think I'll create a separate project, because the Image module team never responded. =(

That project could work with ImageAPI and ImageCache too... I'll have a think about possible methods and maybe start a new issue to discuss it.

I don't think it makes sense to include ImageField, as it is an extension of FileField so not really specifically image related - more just a set of special handlers for FileField files. A FileField service might be nice, which should include ImageField support, but that's a different project again! I don't know if anyone else is looking at this? My team at Defaqto have written something transferring images via web services using ImageField, so I'll ask them to see if it could/should be a separate module. At the moment it's knitted in to Content Distribution.

Greg

Ps - Views will be core for D7, I hope! If not, then surely for D8, so makes sense to include it... =)

PGiro’s picture

greg, did you ever create that image service ?

greg.harvey’s picture

It's in comment #1 of this thread! ;-)

You just have to copy and paste it to a image_service.module file (and obviously provide an image_service.info file). I thought I'd raised it with the Image module guys, but I can't find the issue right now. Weird! It needs to be part of their package. Feel free to raise an issue over there about this module and point them to this thread.

PGiro’s picture

@greg: ok, did you ever get around to writing an upload service ? Do you know if there is one, it's not in the services module

greg.harvey’s picture

Don't know what you mean by an upload service? There *is* a file service in the Services module. I wrote the first version.

PGiro’s picture

Matt, I just double-checked the CVS repository and I only see file_service_get() and file_service_get_node_files() there.

I mean a service whereby images get saved to the drupal site. My use-case is to have an iphone application create a node that contains a CCK image field.

greg.harvey’s picture

Then that's the existing node.save method. Don't know how it works with CCK, but AFAIK it just invokes the node module's functions and CCK hooks in to them, so it should work fine.

PGiro’s picture

greg,
i) sorry about calling you Matt... got confused with another thread I guess !
ii) thanks for your answer, I'll look into it and post a summary of how it goes here for future reference

jjjames’s picture

Did you ever figure out that ImageField service?
thx

PGiro’s picture

Yes. My requirement was to create a node and always provide a single image.

I created a custom service with the following main method and do a multipart post on the service module by the client

function custom_service_create_picture($text,$feeling) {
        global $user;
        $account=user_load(array('uid'=>$user->uid));

        if ($file = file_save_upload('upload')) {

                // Load the required includes for drupal_execute
  module_load_include('inc', 'node', 'node.pages');
  $node = array('type' => 'picture');

  // Setup form_state
  $form_state = array();
  $form_state['values']['uid'] = $user->uid;
  $form_state['values']['type'] = 'picture';
  $form_state['values']['title'] = "the title";
  $form_state['values']['body'] = $text;

  $form_state['values']['field_image'] = array(
        0=>
         array(
      'fid' => $file->fid,
      'title' => 'Image title',
      'filename' => $file->filename,
      'filepath' => $file->filepath,
      'filesize' => $file->filesize,
      'list' => 0,
        )
  );

  $form_state['values']['op'] = t('Save');

  $ret = drupal_execute('picture_node_form', $form_state, $node);

  // Fetch $nid out of $form_state
  $nid = $form_state['nid'];

  if ($errors = form_get_errors()) {
    return services_error(implode("\n", $errors));
  }
  return $nid;
        } else
        return services_error("No file uploaded !");
}

This is alpha code, it worked one day at 12h30 am and hasn't been tested since

joachim’s picture

Yup, this probably belongs in image module.
(Services API for declaring and defining services is fixed now, right...?)

Feel free to reassign and reopen this issue and provide a patch :D

joachim’s picture

One thing though: is there any stuff that should be common to image / imagefield?

greg.harvey’s picture

Project: Services » Image
Component: Code » image.module

Let's move it to your queue then. =)

ImageField would need an entirely different method. Better to write a separate ImageField service. Frankly, it would be easier - the full file objects would already be available in the selected node. You'd just have to ask for select node *and* field name and remember to loop through for multiple values, if applicable.

But that's a whole other conversation and a whole other module. I'm amazed no one's written it yet. It wouldn't take long.

greg.harvey’s picture

Status: Closed (won't fix) » Needs review

Setting to needs review. Suspect original code will still work.

joachim’s picture

Status: Needs review » Needs work

Cool.

I haven't time to look at this myself.

Though, briefly:

image_service_get_images_access()

There's really no need for this function to exist!

          $fid = db_result(db_query("SELECT fid FROM {image} WHERE nid = %d AND image_size = '%s'", $nid, $type));
        $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE fid = %d AND filename = '%s'", $fid, $type));

Could both those be turned into one query? SELECT f.* from {files} f JOIN {image}.... ?

I'll commit this with the rework if it gets:
- 2 positive reviews with the latest Services (6.x-2.0-beta1 as of today!)
- a @file comment stating which version of Services the module needs

adub’s picture

I'm using this with services 6.x-2.0 and it's looking good. However had to change the line:

$fullpath = $_SERVER['DOCUMENT_ROOT'] . base_path() . $path;

to

$fullpath = realpath($path);

+1 for adding to image module

sun’s picture

Title: New image service » Integrate with Services API
Status: Needs work » Active

No patch here. Additionally, I'm not sure whether it is a good idea to work on new features at this stage.

joachim’s picture

It doesn't have any impact at all on the rest of the module, as it's just providing a way for something else to hook into the API.

So I'm happy to review a patch and commit it :)
However, I notice it's been two months since my last review and nobody's done anything with it so it may well be nothing comes of this anyway...

greg.harvey’s picture

Seems no one needs it any more. What's the future of the Image module's image storage anyway? Is their intent to make it use file fields since they are in the core of Drupal 7? If so, there'll probably be nothing to do, as the Services API/Views integration will already spit out base64 encoded file fields (I think - and if it doesn't it would be a much more sensible place to divert efforts to). Could bat this back to the Services team as a feature request against fields integration for Drupal 7.

joachim’s picture

Is there an issue open for how to tackle Image 7?
At any rate, it's conversion to D7 FieldAPI with the help of this: http://drupal.org/project/field_convert

Slocombe3000’s picture

Would this service be simply to retrieve the images from the image node, or would it be possible to tweak this somehow to allow images to be attached to Image nodes?

The use case for this would be to to find a way to allow remote iphone applications to create image nodes.

joachim’s picture

The code above looks like it just gets images.

No reason why you can't add second service that hooks into our API though.

As I said above: I will review patches :)

sun’s picture

Status: Active » Closed (won't fix)

I'd highly recommend to focus on Services/images in D7 instead. Each feature we're adding at this stage needs a custom and potentially complex (or perhaps even undoable) upgrade path to D7.