uint16_t * oyProfileGetWhitePointRamp( int                 width,
                                       oyProfile_s       * p,
                                       oyOptions_s       * options )
{
  uint16_t    * ramp   = calloc( sizeof(uint16_t), width*3);
  oyImage_s   * input  = oyImage_Create( width, 1, ramp, OY_TYPE_123_16, p, 0 );
  oyImage_s   * output = oyImage_Create( width, 1, ramp, OY_TYPE_123_16, p, 0 );
  int i,j, error, mul = 65536/width;

  oyConversion_s * cc = oyConversion_CreateBasicPixels( input, output, options, NULL);

  for(i = 0; i < width; ++i)
  {
    for(j = 0; j < 3; ++j)
      ramp[i*3 + j] = i * mul;
  }

  if(getenv("OY_DEBUG_WRITE"))
    oyImage_WritePPM( input, "wtpt-effect-raw.ppm", "unaltered gray ramp" );


  oyConversion_Correct( cc, "//" OY_TYPE_STD "/icc_color", 0, NULL);
  error = oyConversion_RunPixels( cc, 0 );
  if(error)
    oyMessageFunc_p( oyMSG_WARN,(oyStruct_s*)p, OY_DBG_FORMAT_
                     "found issue while converting ramp: %d", OY_DBG_ARGS_, error );

  if(getenv("OY_DEBUG_WRITE"))
  {
    oyFilterGraph_s * cc_graph = oyConversion_GetGraph( cc );
    oyFilterNode_s * icc = oyFilterGraph_GetNode( cc_graph, -1, "///icc_color", 0 );
    char * comment = oyjlStringCopy("gray ramp", oyAllocateFunc_);
    const char * ndesc = oyFilterNode_GetText( icc, oyNAME_NAME );
    oyjlStringAdd( &comment, oyAllocateFunc_, oyDeAllocateFunc_, "\n%s", ndesc );
    oyImage_WritePPM( input, "wtpt-effect-gray.ppm", comment );
    oyFree_m_(comment);
    oyFilterGraph_Release( &cc_graph );
    oyFilterNode_Release( &icc );
  }

  oyImage_Release( &input );
  oyImage_Release( &output );

  return ramp;
}
/** @func    oyraFilterPlug_ImageOutputPPMWrite
 *  @brief   implement oyCMMFilter_GetNext_f()
 *
 *  @version Oyranos: 0.3.1
 *  @since   2008/10/07 (Oyranos: 0.1.8)
 *  @date    2011/05/12
 */
int      oyraFilterPlug_ImageOutputPPMWrite (
                                       oyFilterPlug_s    * requestor_plug,
                                       oyPixelAccess_s   * ticket )
{
  oyFilterSocket_s * socket;
  oyFilterNode_s * node = 0;
  oyOptions_s * node_opts = 0;
  int result = 0;
  const char * filename = 0;
  FILE * fp = 0;

  socket = oyFilterPlug_GetSocket( requestor_plug );
  node = oyFilterSocket_GetNode( socket );
  node_opts = oyFilterNode_GetOptions( node, 0 );

  /* to reuse the requestor_plug is a exception for the starting request */
  if(node)
    result = oyFilterNode_Run( node, requestor_plug, ticket );
  else
    result = 1;

  if(result <= 0)
    filename = oyOptions_FindString( node_opts, "filename", 0 );

  if(filename)
    fp = fopen( filename, "wb" );

  if(fp)
  {
    oyImage_s *image_output = (oyImage_s*)oyFilterSocket_GetData( socket );
    const char * comment = oyOptions_FindString( node_opts, "comment", NULL );

    fclose (fp); fp = 0;

    result = oyImage_WritePPM( image_output, filename,
                               comment ? comment :
                               oyFilterNode_GetRelatives( node ) );
  }

  return result;
}
int      oyProfile_CreateEffectVCGT  ( oyProfile_s       * prof )
{
  int error = 0;
  /* 2. get user effect profile and display white point effect */
  /* 2.1. get effect profile and decide if it can be embedded into a VGCT tag */
  oyOptions_s * module_options = NULL;
  error = oyAddLinearDisplayEffect( &module_options );
  if(error)
    oyMessageFunc_p( oyMSG_WARN,(oyStruct_s*)prof, OY_DBG_FORMAT_
                        "No display effect for monitor profile %d",
                        OY_DBG_ARGS_,
                        error );

  /* 2.2. get the display white point effect */
  error = oyProfileAddWhitePointEffect( prof, &module_options );
  if(error)
    oyMessageFunc_p( oyMSG_WARN,(oyStruct_s*)prof, OY_DBG_FORMAT_
                        "No white for monitor profile %d",
                        OY_DBG_ARGS_,
                        error );

  /* 3. extract a existing VCGT */
  int width = 256;
  uint16_t * vcgt = oyProfile_GetVCGT( prof, &width );
  oyImage_s * img;
  if(vcgt && getenv("OY_DEBUG_WRITE"))
  {
    img = oyImage_Create( width, 1, vcgt, OY_TYPE_123_16, prof, 0 );
    oyImage_WritePPM( img, "wtpt-vcgt.ppm", "vcgt ramp" );
    oyImage_Release( &img );
  }

  /* 4. create conversion, fill ramp and convert */
  uint16_t * ramp = oyProfileGetWhitePointRamp( width, prof, module_options );
  if(ramp && getenv("OY_DEBUG_WRITE"))
  {
    img = oyImage_Create( width, 1, ramp, OY_TYPE_123_16, prof, 0 );
    oyImage_WritePPM( img, "wtpt-effect.ppm", "white point ramp" );
    oyImage_Release( &img );
  }

  /* 5. mix the two ramps */
  uint16_t * mix = NULL;
  if(vcgt)
    mix = calloc( sizeof(uint16_t), width*3);
  int i,j;
  if(mix)
  for(i = 0; i < width; ++i)
    for(j = 0; j < 3; ++j)
    {
      uint16_t v = oyLinInterpolateRampU16c( ramp, width, j, 3, (double)i/(double)width );
      double vd = v / 65535.0;
      mix[i*3+j] = OY_ROUNDp( oyLinInterpolateRampU16c( vcgt, width, j,3, vd ) );
    }
  if(mix && getenv("OY_DEBUG_WRITE"))
  {
    img  = oyImage_Create( width, 1, mix, OY_TYPE_123_16, prof, 0 );
    oyImage_WritePPM( img, "wtpt-mix.ppm", "white point + vcgt" );
    oyImage_Release( &img );
  }

  /* 6. create a new VCGT tag and exchange the tag */
  if((mix || ramp) && oyProfile_SetVCGT( prof, mix?mix:ramp, width ))
  {
    oyMessageFunc_p( oyMSG_WARN,(oyStruct_s*)prof, OY_DBG_FORMAT_
                        "Alter VCGT tag failed",
                        OY_DBG_ARGS_ );
    error = 1;
  }

  if(mix) oyDeAllocateFunc_(mix);
  if(ramp) oyDeAllocateFunc_(ramp);
  if(vcgt) oyDeAllocateFunc_(vcgt);

  return error;
}
/** Function oyDrawScreenImage
 *  @brief   generate a Oyranos image from a given context for display
 *
 *  The function asks the 'oydi' node to provide parameters to render a
 *  oyImage_s from a prepared oyConversion_s context.
 *
 *  @param[in]     context             the Oyranos graph
 *  @param[in,out] ticket              rendering context for tracking
 *                                     rectangles
 *  @param[in]     display_rectangle   absolute coordinates of visible image
 *                                     in relation to display
 *  @param[in,out] old_display_rectangle
 *                                     rembering of display_rectangle
 +  @param[in,out] old_roi_rectangle   remembering of ticket's ROI (optional)
 *  @param[in]     system_type         the system dependent type specification
 *                                     - "X11" is well supported
 *                                     - "oy-test" for internal tests
 *  @param[in]     data_type_request   oyUINT8 or oyUINT16
 *  @param[in]     display             the system display with system_type:
 *                                     - "X11": a Display object
 *  @param[in]     window              the system window with system_type:
 *                                     - "X11": a Window ID
 *  @param[in]     dirty               explicite redraw
 *  @param[out]    image               the image from graph to display
 *  @return                            0 - success, -1 - issue, >=  1 - error
 *
 *  @version Oyranos: 0.9.6
 *  @date    2016/09/22
 *  @since   2010/09/05 (Oyranos: 0.1.11)
 */
int  oyDrawScreenImage               ( oyConversion_s    * context,
                                       oyPixelAccess_s   * ticket,
                                       oyRectangle_s     * display_rectangle,
                                       oyRectangle_s     * old_display_rectangle,
                                       oyRectangle_s     * old_roi_rectangle,
                                       const char        * system_type,
                                       oyDATATYPE_e        data_type_request,
                                       void              * display,
                                       void              * window,
                                       int                 dirty,
                                       oyImage_s         * image )
{
  int result = 0;

    if(context)
    {
      double X,Y,W,H;
      int channels = 0;
      oyFilterNode_s * node_out = 0;
      oyRectangle_s * disp_rectangle = 0,
                    * ticket_roi = 0;
      oyOptions_s * image_tags = 0;
      oyDATATYPE_e data_type = oyUINT8;
      oyPixel_t pt = 0;

      oyRectangle_GetGeo( display_rectangle, &X, &Y, &W, &H );

      if(!image)
        return 1;
      if( W <= 0 || H <= 0)
        return -1;

      image_tags = oyImage_GetTags( image );

      if(window && strcmp("X11", system_type) == 0)
      {
#if defined(XCM_HAVE_X11)
        /* add X11 window and display identifiers to output image */
        oyOption_s * o = 0;
        Display *disp = (Display*) display;
        Window  w = (Window) window;
        int count = oyOptions_CountType( image_tags,
                                         "//" OY_TYPE_STD "/display/window_id",
                                         oyOBJECT_BLOB_S );
        if(!count && w)
        {
          oyBlob_s * win_id = oyBlob_New(0),
                   * display_id = oyBlob_New(0);
          if(win_id)
          {
            oyBlob_SetFromStatic( win_id, (oyPointer)w, 0, 0 );
            o = oyOption_FromRegistration( "//" OY_TYPE_STD "/display/window_id",
                                           0 );
            oyOption_MoveInStruct( o, (oyStruct_s**)&win_id );
            oyOptions_MoveIn( image_tags, &o, -1 );

            oyBlob_SetFromStatic( display_id, (oyPointer)disp, 0, 0 );
            o = oyOption_FromRegistration( "//" OY_TYPE_STD "/display/display_id",
                                           0 );
            oyOption_MoveInStruct( o, (oyStruct_s**)&display_id );
            oyOptions_MoveIn( image_tags, &o, -1 );

            oyOptions_SetFromText( &image_tags,
                                   "//" OY_TYPE_STD "/display/display_name",
                                   DisplayString(disp), OY_CREATE_NEW );

          } else
            printf("%s:%d WARNING: no X11 Window obtained or\n"
                   "   no oyBlob_s allocateable\n", __FILE__,__LINE__);

        }
#endif
      } else if(strcmp("oy-test", system_type) == 0)
        oyOptions_SetFromText( &image_tags,
                               "//" OY_TYPE_STD "/display/display_name",
                               system_type, OY_CREATE_NEW );

      /* check if the actual data can be displayed */
      pt = oyImage_GetPixelLayout( image, oyLAYOUT );
      data_type = oyToDataType_m( pt );
      channels = oyToChannels_m( pt );
      if(pt != 0 &&
         ((channels != 4 && channels != 3) || data_type != data_type_request))
      {
        printf( "%s:%d WARNING: wrong image data format: %s\n%s\n"
                "need 4 or 3 channels with %s\n", __FILE__,__LINE__,
                oyOptions_FindString( image_tags, "filename", 0 ),
                image ? oyObject_GetName( image->oy_, oyNAME_NICK ) : "",
                oyDataTypeToText( data_type_request ) );
        return 1;
      }


      /* Inform about the images display coverage.  */
      disp_rectangle = (oyRectangle_s*) oyOptions_GetType( image_tags, -1,
                                    "display_rectangle", oyOBJECT_RECTANGLE_S );
      oyRectangle_SetGeo( disp_rectangle, X,Y,W,H );


      node_out = oyConversion_GetNode( context, OY_OUTPUT );
      ticket_roi = oyPixelAccess_GetArrayROI( ticket );
      /* decide wether to refresh the cached rectangle of our static image */
      if( node_out &&
          /* Did the window area move? */
         ((!oyRectangle_IsEqual( disp_rectangle, old_display_rectangle ) ||
           /* Something explicite to update? */
           (old_roi_rectangle &&
            !oyRectangle_IsEqual( ticket_roi, old_roi_rectangle ))||
           /* Did the image move? */
           oyPixelAccess_GetStart( ticket,0 ) !=
           oyPixelAccess_GetOldStart( ticket,0 ) ||
           oyPixelAccess_GetStart( ticket,1 ) !=
           oyPixelAccess_GetOldStart( ticket,1 )) ||
           dirty > 0))
      {
#ifdef DEBUG_
        printf( "%s:%d new display rectangle: %s +%d+%d\n", __FILE__,__LINE__,
                oyRectangle_Show(disp_rectangle), X, Y ),
#endif

        /* convert the image data */
        oyConversion_RunPixels( context, ticket );

        if(oy_debug && getenv("OY_DEBUG_WRITE"))
        {
          oyImage_s * out = oyConversion_GetImage( context, OY_OUTPUT );
          oyImage_WritePPM( out, "debug_image_out.ppm", "image_display output image");
          oyImage_Release( &out );
        }

        /* remember the old rectangle */
        oyRectangle_SetByRectangle( old_display_rectangle, disp_rectangle );
        oyRectangle_SetByRectangle( old_roi_rectangle, ticket_roi );
        oyPixelAccess_SetOldStart(ticket,0, oyPixelAccess_GetStart(ticket,0));
        oyPixelAccess_SetOldStart(ticket,1, oyPixelAccess_GetStart(ticket,1));
      } else
        result = -1;

      oyFilterNode_Release( &node_out );
      oyOptions_Release( &image_tags );
      oyRectangle_Release( &disp_rectangle );
      oyRectangle_Release( &ticket_roi );
    }

  if(oy_debug >= 4)
    fprintf( stderr, "%s:%d %s() result: %d\n", strrchr(__FILE__,'/'),__LINE__,__func__, result );
  return result;
}