github.com/unidoc/unidoc@v2.2.0+incompatible/pdf/model/shading.go (about)

     1  /*
     2   * This file is subject to the terms and conditions defined in
     3   * file 'LICENSE.md', which is part of this source code package.
     4   */
     5  
     6  package model
     7  
     8  import (
     9  	"errors"
    10  
    11  	"github.com/unidoc/unidoc/common"
    12  	. "github.com/unidoc/unidoc/pdf/core"
    13  )
    14  
    15  // There are 7 types of shading, indicated by the shading type variable:
    16  // 1: Function-based shading.
    17  // 2: Axial shading.
    18  // 3: Radial shading.
    19  // 4: Free-form Gouraud-shaded triangle mesh.
    20  // 5: Lattice-form Gouraud-shaded triangle mesh.
    21  // 6: Coons patch mesh.
    22  // 7: Tensor-product patch mesh.
    23  // types 4-7 are contained in a stream object, where the dictionary is given by the stream dictionary.
    24  type PdfShading struct {
    25  	ShadingType *PdfObjectInteger
    26  	ColorSpace  PdfColorspace
    27  	Background  *PdfObjectArray
    28  	BBox        *PdfRectangle
    29  	AntiAlias   *PdfObjectBool
    30  
    31  	context   PdfModel  // The sub shading type entry (types 1-7).  Represented by PdfShadingType1-7.
    32  	container PdfObject // The container.  Can be stream, indirect object, or dictionary.
    33  }
    34  
    35  func (this *PdfShading) GetContainingPdfObject() PdfObject {
    36  	return this.container
    37  }
    38  
    39  // Context in this case is a reference to the subshading entry as represented by PdfShadingType1-7.
    40  func (this *PdfShading) GetContext() PdfModel {
    41  	return this.context
    42  }
    43  
    44  // Set the sub annotation (context).
    45  func (this *PdfShading) SetContext(ctx PdfModel) {
    46  	this.context = ctx
    47  }
    48  
    49  func (this *PdfShading) getShadingDict() (*PdfObjectDictionary, error) {
    50  	obj := this.container
    51  
    52  	if indObj, isInd := obj.(*PdfIndirectObject); isInd {
    53  		d, ok := indObj.PdfObject.(*PdfObjectDictionary)
    54  		if !ok {
    55  			return nil, ErrTypeError
    56  		}
    57  
    58  		return d, nil
    59  	} else if streamObj, isStream := obj.(*PdfObjectStream); isStream {
    60  		return streamObj.PdfObjectDictionary, nil
    61  	} else if d, isDict := obj.(*PdfObjectDictionary); isDict {
    62  		return d, nil
    63  	} else {
    64  		common.Log.Debug("Unable to access shading dictionary")
    65  		return nil, ErrTypeError
    66  	}
    67  }
    68  
    69  // Shading type 1: Function-based shading.
    70  type PdfShadingType1 struct {
    71  	*PdfShading
    72  	Domain   *PdfObjectArray
    73  	Matrix   *PdfObjectArray
    74  	Function []PdfFunction
    75  }
    76  
    77  // Shading type 2: Axial shading.
    78  type PdfShadingType2 struct {
    79  	*PdfShading
    80  	Coords   *PdfObjectArray
    81  	Domain   *PdfObjectArray
    82  	Function []PdfFunction
    83  	Extend   *PdfObjectArray
    84  }
    85  
    86  // Shading type 3: Radial shading.
    87  type PdfShadingType3 struct {
    88  	*PdfShading
    89  	Coords   *PdfObjectArray
    90  	Domain   *PdfObjectArray
    91  	Function []PdfFunction
    92  	Extend   *PdfObjectArray
    93  }
    94  
    95  // Shading type 4: Free-form Gouraud-shaded triangle mesh.
    96  type PdfShadingType4 struct {
    97  	*PdfShading
    98  	BitsPerCoordinate *PdfObjectInteger
    99  	BitsPerComponent  *PdfObjectInteger
   100  	BitsPerFlag       *PdfObjectInteger
   101  	Decode            *PdfObjectArray
   102  	Function          []PdfFunction
   103  }
   104  
   105  // Shading type 5: Lattice-form Gouraud-shaded triangle mesh.
   106  type PdfShadingType5 struct {
   107  	*PdfShading
   108  	BitsPerCoordinate *PdfObjectInteger
   109  	BitsPerComponent  *PdfObjectInteger
   110  	VerticesPerRow    *PdfObjectInteger
   111  	Decode            *PdfObjectArray
   112  	Function          []PdfFunction
   113  }
   114  
   115  // Shading type 6: Coons patch mesh.
   116  type PdfShadingType6 struct {
   117  	*PdfShading
   118  	BitsPerCoordinate *PdfObjectInteger
   119  	BitsPerComponent  *PdfObjectInteger
   120  	BitsPerFlag       *PdfObjectInteger
   121  	Decode            *PdfObjectArray
   122  	Function          []PdfFunction
   123  }
   124  
   125  // Shading type 7: Tensor-product patch mesh.
   126  type PdfShadingType7 struct {
   127  	*PdfShading
   128  	BitsPerCoordinate *PdfObjectInteger
   129  	BitsPerComponent  *PdfObjectInteger
   130  	BitsPerFlag       *PdfObjectInteger
   131  	Decode            *PdfObjectArray
   132  	Function          []PdfFunction
   133  }
   134  
   135  // Used for PDF parsing. Loads the PDF shading from a PDF object.
   136  // Can be either an indirect object (types 1-3) containing the dictionary, or a stream object with the stream
   137  // dictionary containing the shading dictionary (types 4-7).
   138  func newPdfShadingFromPdfObject(obj PdfObject) (*PdfShading, error) {
   139  	shading := &PdfShading{}
   140  
   141  	var dict *PdfObjectDictionary
   142  	if indObj, isInd := obj.(*PdfIndirectObject); isInd {
   143  		shading.container = indObj
   144  
   145  		d, ok := indObj.PdfObject.(*PdfObjectDictionary)
   146  		if !ok {
   147  			common.Log.Debug("Object not a dictionary type")
   148  			return nil, ErrTypeError
   149  		}
   150  
   151  		dict = d
   152  	} else if streamObj, isStream := obj.(*PdfObjectStream); isStream {
   153  		shading.container = streamObj
   154  		dict = streamObj.PdfObjectDictionary
   155  	} else if d, isDict := obj.(*PdfObjectDictionary); isDict {
   156  		shading.container = d
   157  		dict = d
   158  	} else {
   159  		common.Log.Debug("Object type unexpected (%T)", obj)
   160  		return nil, ErrTypeError
   161  	}
   162  
   163  	if dict == nil {
   164  		common.Log.Debug("Dictionary missing")
   165  		return nil, errors.New("Dict missing")
   166  	}
   167  
   168  	// Shading type (required).
   169  	obj = dict.Get("ShadingType")
   170  	if obj == nil {
   171  		common.Log.Debug("Required shading type missing")
   172  		return nil, ErrRequiredAttributeMissing
   173  	}
   174  	obj = TraceToDirectObject(obj)
   175  	shadingType, ok := obj.(*PdfObjectInteger)
   176  	if !ok {
   177  		common.Log.Debug("Invalid type for shading type (%T)", obj)
   178  		return nil, ErrTypeError
   179  	}
   180  	if *shadingType < 1 || *shadingType > 7 {
   181  		common.Log.Debug("Invalid shading type, not 1-7 (got %d)", *shadingType)
   182  		return nil, ErrTypeError
   183  	}
   184  	shading.ShadingType = shadingType
   185  
   186  	// Color space (required).
   187  	obj = dict.Get("ColorSpace")
   188  	if obj == nil {
   189  		common.Log.Debug("Required ColorSpace entry missing")
   190  		return nil, ErrRequiredAttributeMissing
   191  	}
   192  	cs, err := NewPdfColorspaceFromPdfObject(obj)
   193  	if err != nil {
   194  		common.Log.Debug("Failed loading colorspace: %v", err)
   195  		return nil, err
   196  	}
   197  	shading.ColorSpace = cs
   198  
   199  	// Background (optional). Array of color components.
   200  	obj = dict.Get("Background")
   201  	if obj != nil {
   202  		obj = TraceToDirectObject(obj)
   203  		arr, ok := obj.(*PdfObjectArray)
   204  		if !ok {
   205  			common.Log.Debug("Background should be specified by an array (got %T)", obj)
   206  			return nil, ErrTypeError
   207  		}
   208  		shading.Background = arr
   209  	}
   210  
   211  	// BBox.
   212  	obj = dict.Get("BBox")
   213  	if obj != nil {
   214  		obj = TraceToDirectObject(obj)
   215  		arr, ok := obj.(*PdfObjectArray)
   216  		if !ok {
   217  			common.Log.Debug("Background should be specified by an array (got %T)", obj)
   218  			return nil, ErrTypeError
   219  		}
   220  		rect, err := NewPdfRectangle(*arr)
   221  		if err != nil {
   222  			common.Log.Debug("BBox error: %v", err)
   223  			return nil, err
   224  		}
   225  		shading.BBox = rect
   226  	}
   227  
   228  	// AntiAlias.
   229  	obj = dict.Get("AntiAlias")
   230  	if obj != nil {
   231  		obj = TraceToDirectObject(obj)
   232  		val, ok := obj.(*PdfObjectBool)
   233  		if !ok {
   234  			common.Log.Debug("AntiAlias invalid type, should be bool (got %T)", obj)
   235  			return nil, ErrTypeError
   236  		}
   237  		shading.AntiAlias = val
   238  	}
   239  
   240  	// Load specific shading type specific entries.
   241  	switch *shadingType {
   242  	case 1:
   243  		ctx, err := newPdfShadingType1FromDictionary(dict)
   244  		if err != nil {
   245  			return nil, err
   246  		}
   247  		ctx.PdfShading = shading
   248  		shading.context = ctx
   249  		return shading, nil
   250  	case 2:
   251  		ctx, err := newPdfShadingType2FromDictionary(dict)
   252  		if err != nil {
   253  			return nil, err
   254  		}
   255  		ctx.PdfShading = shading
   256  		shading.context = ctx
   257  		return shading, nil
   258  	case 3:
   259  		ctx, err := newPdfShadingType3FromDictionary(dict)
   260  		if err != nil {
   261  			return nil, err
   262  		}
   263  		ctx.PdfShading = shading
   264  		shading.context = ctx
   265  		return shading, nil
   266  	case 4:
   267  		ctx, err := newPdfShadingType4FromDictionary(dict)
   268  		if err != nil {
   269  			return nil, err
   270  		}
   271  		ctx.PdfShading = shading
   272  		shading.context = ctx
   273  		return shading, nil
   274  	case 5:
   275  		ctx, err := newPdfShadingType5FromDictionary(dict)
   276  		if err != nil {
   277  			return nil, err
   278  		}
   279  		ctx.PdfShading = shading
   280  		shading.context = ctx
   281  		return shading, nil
   282  	case 6:
   283  		ctx, err := newPdfShadingType6FromDictionary(dict)
   284  		if err != nil {
   285  			return nil, err
   286  		}
   287  		ctx.PdfShading = shading
   288  		shading.context = ctx
   289  		return shading, nil
   290  	case 7:
   291  		ctx, err := newPdfShadingType7FromDictionary(dict)
   292  		if err != nil {
   293  			return nil, err
   294  		}
   295  		ctx.PdfShading = shading
   296  		shading.context = ctx
   297  		return shading, nil
   298  	}
   299  
   300  	return nil, errors.New("Unknown shading type")
   301  }
   302  
   303  // Load shading type 1 specific attributes from pdf object.  Used in parsing/loading PDFs.
   304  func newPdfShadingType1FromDictionary(dict *PdfObjectDictionary) (*PdfShadingType1, error) {
   305  	shading := PdfShadingType1{}
   306  
   307  	// Domain (optional).
   308  	if obj := dict.Get("Domain"); obj != nil {
   309  		obj = TraceToDirectObject(obj)
   310  		arr, ok := obj.(*PdfObjectArray)
   311  		if !ok {
   312  			common.Log.Debug("Domain not an array (got %T)", obj)
   313  			return nil, errors.New("Type check error")
   314  		}
   315  		shading.Domain = arr
   316  	}
   317  
   318  	// Matrix (optional).
   319  	if obj := dict.Get("Matrix"); obj != nil {
   320  		obj = TraceToDirectObject(obj)
   321  		arr, ok := obj.(*PdfObjectArray)
   322  		if !ok {
   323  			common.Log.Debug("Matrix not an array (got %T)", obj)
   324  			return nil, errors.New("Type check error")
   325  		}
   326  		shading.Matrix = arr
   327  	}
   328  
   329  	// Function (required).
   330  	obj := dict.Get("Function")
   331  	if obj == nil {
   332  		common.Log.Debug("Required attribute missing:  Function")
   333  		return nil, ErrRequiredAttributeMissing
   334  	}
   335  	shading.Function = []PdfFunction{}
   336  	if array, is := obj.(*PdfObjectArray); is {
   337  		for _, obj := range *array {
   338  			function, err := newPdfFunctionFromPdfObject(obj)
   339  			if err != nil {
   340  				common.Log.Debug("Error parsing function: %v", err)
   341  				return nil, err
   342  			}
   343  			shading.Function = append(shading.Function, function)
   344  		}
   345  	} else {
   346  		function, err := newPdfFunctionFromPdfObject(obj)
   347  		if err != nil {
   348  			common.Log.Debug("Error parsing function: %v", err)
   349  			return nil, err
   350  		}
   351  		shading.Function = append(shading.Function, function)
   352  	}
   353  
   354  	return &shading, nil
   355  }
   356  
   357  // Load shading type 2 specific attributes from pdf object.  Used in parsing/loading PDFs.
   358  func newPdfShadingType2FromDictionary(dict *PdfObjectDictionary) (*PdfShadingType2, error) {
   359  	shading := PdfShadingType2{}
   360  
   361  	// Coords (required).
   362  	obj := dict.Get("Coords")
   363  	if obj == nil {
   364  		common.Log.Debug("Required attribute missing:  Coords")
   365  		return nil, ErrRequiredAttributeMissing
   366  	}
   367  	arr, ok := obj.(*PdfObjectArray)
   368  	if !ok {
   369  		common.Log.Debug("Coords not an array (got %T)", obj)
   370  		return nil, errors.New("Type check error")
   371  	}
   372  	if len(*arr) != 4 {
   373  		common.Log.Debug("Coords length not 4 (got %d)", len(*arr))
   374  		return nil, errors.New("Invalid attribute")
   375  	}
   376  	shading.Coords = arr
   377  
   378  	// Domain (optional).
   379  	if obj := dict.Get("Domain"); obj != nil {
   380  		obj = TraceToDirectObject(obj)
   381  		arr, ok := obj.(*PdfObjectArray)
   382  		if !ok {
   383  			common.Log.Debug("Domain not an array (got %T)", obj)
   384  			return nil, errors.New("Type check error")
   385  		}
   386  		shading.Domain = arr
   387  	}
   388  
   389  	// Function (required).
   390  	obj = dict.Get("Function")
   391  	if obj == nil {
   392  		common.Log.Debug("Required attribute missing:  Function")
   393  		return nil, ErrRequiredAttributeMissing
   394  	}
   395  	shading.Function = []PdfFunction{}
   396  	if array, is := obj.(*PdfObjectArray); is {
   397  		for _, obj := range *array {
   398  			function, err := newPdfFunctionFromPdfObject(obj)
   399  			if err != nil {
   400  				common.Log.Debug("Error parsing function: %v", err)
   401  				return nil, err
   402  			}
   403  			shading.Function = append(shading.Function, function)
   404  		}
   405  	} else {
   406  		function, err := newPdfFunctionFromPdfObject(obj)
   407  		if err != nil {
   408  			common.Log.Debug("Error parsing function: %v", err)
   409  			return nil, err
   410  		}
   411  		shading.Function = append(shading.Function, function)
   412  	}
   413  
   414  	// Extend (optional).
   415  	if obj := dict.Get("Extend"); obj != nil {
   416  		obj = TraceToDirectObject(obj)
   417  		arr, ok := obj.(*PdfObjectArray)
   418  		if !ok {
   419  			common.Log.Debug("Matrix not an array (got %T)", obj)
   420  			return nil, ErrTypeCheck
   421  		}
   422  		if len(*arr) != 2 {
   423  			common.Log.Debug("Extend length not 2 (got %d)", len(*arr))
   424  			return nil, ErrInvalidAttribute
   425  		}
   426  		shading.Extend = arr
   427  	}
   428  
   429  	return &shading, nil
   430  }
   431  
   432  // Load shading type 3 specific attributes from pdf object.  Used in parsing/loading PDFs.
   433  func newPdfShadingType3FromDictionary(dict *PdfObjectDictionary) (*PdfShadingType3, error) {
   434  	shading := PdfShadingType3{}
   435  
   436  	// Coords (required).
   437  	obj := dict.Get("Coords")
   438  	if obj == nil {
   439  		common.Log.Debug("Required attribute missing: Coords")
   440  		return nil, ErrRequiredAttributeMissing
   441  	}
   442  	arr, ok := obj.(*PdfObjectArray)
   443  	if !ok {
   444  		common.Log.Debug("Coords not an array (got %T)", obj)
   445  		return nil, ErrTypeError
   446  	}
   447  	if len(*arr) != 6 {
   448  		common.Log.Debug("Coords length not 6 (got %d)", len(*arr))
   449  		return nil, ErrInvalidAttribute
   450  	}
   451  	shading.Coords = arr
   452  
   453  	// Domain (optional).
   454  	if obj := dict.Get("Domain"); obj != nil {
   455  		obj = TraceToDirectObject(obj)
   456  		arr, ok := obj.(*PdfObjectArray)
   457  		if !ok {
   458  			common.Log.Debug("Domain not an array (got %T)", obj)
   459  			return nil, ErrTypeError
   460  		}
   461  		shading.Domain = arr
   462  	}
   463  
   464  	// Function (required).
   465  	obj = dict.Get("Function")
   466  	if obj == nil {
   467  		common.Log.Debug("Required attribute missing:  Function")
   468  		return nil, ErrRequiredAttributeMissing
   469  	}
   470  	shading.Function = []PdfFunction{}
   471  	if array, is := obj.(*PdfObjectArray); is {
   472  		for _, obj := range *array {
   473  			function, err := newPdfFunctionFromPdfObject(obj)
   474  			if err != nil {
   475  				common.Log.Debug("Error parsing function: %v", err)
   476  				return nil, err
   477  			}
   478  			shading.Function = append(shading.Function, function)
   479  		}
   480  	} else {
   481  		function, err := newPdfFunctionFromPdfObject(obj)
   482  		if err != nil {
   483  			common.Log.Debug("Error parsing function: %v", err)
   484  			return nil, err
   485  		}
   486  		shading.Function = append(shading.Function, function)
   487  	}
   488  
   489  	// Extend (optional).
   490  	if obj := dict.Get("Extend"); obj != nil {
   491  		obj = TraceToDirectObject(obj)
   492  		arr, ok := obj.(*PdfObjectArray)
   493  		if !ok {
   494  			common.Log.Debug("Matrix not an array (got %T)", obj)
   495  			return nil, ErrTypeError
   496  		}
   497  		if len(*arr) != 2 {
   498  			common.Log.Debug("Extend length not 2 (got %d)", len(*arr))
   499  			return nil, ErrInvalidAttribute
   500  		}
   501  		shading.Extend = arr
   502  	}
   503  
   504  	return &shading, nil
   505  }
   506  
   507  // Load shading type 4 specific attributes from pdf object.  Used in parsing/loading PDFs.
   508  func newPdfShadingType4FromDictionary(dict *PdfObjectDictionary) (*PdfShadingType4, error) {
   509  	shading := PdfShadingType4{}
   510  
   511  	// BitsPerCoordinate (required).
   512  	obj := dict.Get("BitsPerCoordinate")
   513  	if obj == nil {
   514  		common.Log.Debug("Required attribute missing: BitsPerCoordinate")
   515  		return nil, ErrRequiredAttributeMissing
   516  	}
   517  	integer, ok := obj.(*PdfObjectInteger)
   518  	if !ok {
   519  		common.Log.Debug("BitsPerCoordinate not an integer (got %T)", obj)
   520  		return nil, ErrTypeError
   521  	}
   522  	shading.BitsPerCoordinate = integer
   523  
   524  	// BitsPerComponent (required).
   525  	obj = dict.Get("BitsPerComponent")
   526  	if obj == nil {
   527  		common.Log.Debug("Required attribute missing: BitsPerComponent")
   528  		return nil, ErrRequiredAttributeMissing
   529  	}
   530  	integer, ok = obj.(*PdfObjectInteger)
   531  	if !ok {
   532  		common.Log.Debug("BitsPerComponent not an integer (got %T)", obj)
   533  		return nil, ErrTypeError
   534  	}
   535  	shading.BitsPerComponent = integer
   536  
   537  	// BitsPerFlag (required).
   538  	obj = dict.Get("BitsPerFlag")
   539  	if obj == nil {
   540  		common.Log.Debug("Required attribute missing: BitsPerFlag")
   541  		return nil, ErrRequiredAttributeMissing
   542  	}
   543  	integer, ok = obj.(*PdfObjectInteger)
   544  	if !ok {
   545  		common.Log.Debug("BitsPerFlag not an integer (got %T)", obj)
   546  		return nil, ErrTypeError
   547  	}
   548  	shading.BitsPerComponent = integer
   549  
   550  	// Decode (required).
   551  	obj = dict.Get("Decode")
   552  	if obj == nil {
   553  		common.Log.Debug("Required attribute missing: Decode")
   554  		return nil, ErrRequiredAttributeMissing
   555  	}
   556  	arr, ok := obj.(*PdfObjectArray)
   557  	if !ok {
   558  		common.Log.Debug("Decode not an array (got %T)", obj)
   559  		return nil, ErrTypeError
   560  	}
   561  	shading.Decode = arr
   562  
   563  	// Function (required).
   564  	obj = dict.Get("Function")
   565  	if obj == nil {
   566  		common.Log.Debug("Required attribute missing:  Function")
   567  		return nil, ErrRequiredAttributeMissing
   568  	}
   569  	shading.Function = []PdfFunction{}
   570  	if array, is := obj.(*PdfObjectArray); is {
   571  		for _, obj := range *array {
   572  			function, err := newPdfFunctionFromPdfObject(obj)
   573  			if err != nil {
   574  				common.Log.Debug("Error parsing function: %v", err)
   575  				return nil, err
   576  			}
   577  			shading.Function = append(shading.Function, function)
   578  		}
   579  	} else {
   580  		function, err := newPdfFunctionFromPdfObject(obj)
   581  		if err != nil {
   582  			common.Log.Debug("Error parsing function: %v", err)
   583  			return nil, err
   584  		}
   585  		shading.Function = append(shading.Function, function)
   586  	}
   587  
   588  	return &shading, nil
   589  }
   590  
   591  // Load shading type 5 specific attributes from pdf object.  Used in parsing/loading PDFs.
   592  func newPdfShadingType5FromDictionary(dict *PdfObjectDictionary) (*PdfShadingType5, error) {
   593  	shading := PdfShadingType5{}
   594  
   595  	// BitsPerCoordinate (required).
   596  	obj := dict.Get("BitsPerCoordinate")
   597  	if obj == nil {
   598  		common.Log.Debug("Required attribute missing: BitsPerCoordinate")
   599  		return nil, ErrRequiredAttributeMissing
   600  	}
   601  	integer, ok := obj.(*PdfObjectInteger)
   602  	if !ok {
   603  		common.Log.Debug("BitsPerCoordinate not an integer (got %T)", obj)
   604  		return nil, ErrTypeError
   605  	}
   606  	shading.BitsPerCoordinate = integer
   607  
   608  	// BitsPerComponent (required).
   609  	obj = dict.Get("BitsPerComponent")
   610  	if obj == nil {
   611  		common.Log.Debug("Required attribute missing: BitsPerComponent")
   612  		return nil, ErrRequiredAttributeMissing
   613  	}
   614  	integer, ok = obj.(*PdfObjectInteger)
   615  	if !ok {
   616  		common.Log.Debug("BitsPerComponent not an integer (got %T)", obj)
   617  		return nil, ErrTypeError
   618  	}
   619  	shading.BitsPerComponent = integer
   620  
   621  	// VerticesPerRow (required).
   622  	obj = dict.Get("VerticesPerRow")
   623  	if obj == nil {
   624  		common.Log.Debug("Required attribute missing: VerticesPerRow")
   625  		return nil, ErrRequiredAttributeMissing
   626  	}
   627  	integer, ok = obj.(*PdfObjectInteger)
   628  	if !ok {
   629  		common.Log.Debug("VerticesPerRow not an integer (got %T)", obj)
   630  		return nil, ErrTypeError
   631  	}
   632  	shading.VerticesPerRow = integer
   633  
   634  	// Decode (required).
   635  	obj = dict.Get("Decode")
   636  	if obj == nil {
   637  		common.Log.Debug("Required attribute missing: Decode")
   638  		return nil, ErrRequiredAttributeMissing
   639  	}
   640  	arr, ok := obj.(*PdfObjectArray)
   641  	if !ok {
   642  		common.Log.Debug("Decode not an array (got %T)", obj)
   643  		return nil, ErrTypeError
   644  	}
   645  	shading.Decode = arr
   646  
   647  	// Function (optional).
   648  	if obj := dict.Get("Function"); obj != nil {
   649  		// Function (required).
   650  		shading.Function = []PdfFunction{}
   651  		if array, is := obj.(*PdfObjectArray); is {
   652  			for _, obj := range *array {
   653  				function, err := newPdfFunctionFromPdfObject(obj)
   654  				if err != nil {
   655  					common.Log.Debug("Error parsing function: %v", err)
   656  					return nil, err
   657  				}
   658  				shading.Function = append(shading.Function, function)
   659  			}
   660  		} else {
   661  			function, err := newPdfFunctionFromPdfObject(obj)
   662  			if err != nil {
   663  				common.Log.Debug("Error parsing function: %v", err)
   664  				return nil, err
   665  			}
   666  			shading.Function = append(shading.Function, function)
   667  		}
   668  	}
   669  
   670  	return &shading, nil
   671  }
   672  
   673  // Load shading type 6 specific attributes from pdf object.  Used in parsing/loading PDFs.
   674  func newPdfShadingType6FromDictionary(dict *PdfObjectDictionary) (*PdfShadingType6, error) {
   675  	shading := PdfShadingType6{}
   676  
   677  	// BitsPerCoordinate (required).
   678  	obj := dict.Get("BitsPerCoordinate")
   679  	if obj == nil {
   680  		common.Log.Debug("Required attribute missing: BitsPerCoordinate")
   681  		return nil, ErrRequiredAttributeMissing
   682  	}
   683  	integer, ok := obj.(*PdfObjectInteger)
   684  	if !ok {
   685  		common.Log.Debug("BitsPerCoordinate not an integer (got %T)", obj)
   686  		return nil, ErrTypeError
   687  	}
   688  	shading.BitsPerCoordinate = integer
   689  
   690  	// BitsPerComponent (required).
   691  	obj = dict.Get("BitsPerComponent")
   692  	if obj == nil {
   693  		common.Log.Debug("Required attribute missing: BitsPerComponent")
   694  		return nil, ErrRequiredAttributeMissing
   695  	}
   696  	integer, ok = obj.(*PdfObjectInteger)
   697  	if !ok {
   698  		common.Log.Debug("BitsPerComponent not an integer (got %T)", obj)
   699  		return nil, ErrTypeError
   700  	}
   701  	shading.BitsPerComponent = integer
   702  
   703  	// BitsPerFlag (required).
   704  	obj = dict.Get("BitsPerFlag")
   705  	if obj == nil {
   706  		common.Log.Debug("Required attribute missing: BitsPerFlag")
   707  		return nil, ErrRequiredAttributeMissing
   708  	}
   709  	integer, ok = obj.(*PdfObjectInteger)
   710  	if !ok {
   711  		common.Log.Debug("BitsPerFlag not an integer (got %T)", obj)
   712  		return nil, ErrTypeError
   713  	}
   714  	shading.BitsPerComponent = integer
   715  
   716  	// Decode (required).
   717  	obj = dict.Get("Decode")
   718  	if obj == nil {
   719  		common.Log.Debug("Required attribute missing: Decode")
   720  		return nil, ErrRequiredAttributeMissing
   721  	}
   722  	arr, ok := obj.(*PdfObjectArray)
   723  	if !ok {
   724  		common.Log.Debug("Decode not an array (got %T)", obj)
   725  		return nil, ErrTypeError
   726  	}
   727  	shading.Decode = arr
   728  
   729  	// Function (optional).
   730  	if obj := dict.Get("Function"); obj != nil {
   731  		shading.Function = []PdfFunction{}
   732  		if array, is := obj.(*PdfObjectArray); is {
   733  			for _, obj := range *array {
   734  				function, err := newPdfFunctionFromPdfObject(obj)
   735  				if err != nil {
   736  					common.Log.Debug("Error parsing function: %v", err)
   737  					return nil, err
   738  				}
   739  				shading.Function = append(shading.Function, function)
   740  			}
   741  		} else {
   742  			function, err := newPdfFunctionFromPdfObject(obj)
   743  			if err != nil {
   744  				common.Log.Debug("Error parsing function: %v", err)
   745  				return nil, err
   746  			}
   747  			shading.Function = append(shading.Function, function)
   748  		}
   749  	}
   750  
   751  	return &shading, nil
   752  }
   753  
   754  // Load shading type 7 specific attributes from pdf object.  Used in parsing/loading PDFs.
   755  func newPdfShadingType7FromDictionary(dict *PdfObjectDictionary) (*PdfShadingType7, error) {
   756  	shading := PdfShadingType7{}
   757  
   758  	// BitsPerCoordinate (required).
   759  	obj := dict.Get("BitsPerCoordinate")
   760  	if obj == nil {
   761  		common.Log.Debug("Required attribute missing: BitsPerCoordinate")
   762  		return nil, ErrRequiredAttributeMissing
   763  	}
   764  	integer, ok := obj.(*PdfObjectInteger)
   765  	if !ok {
   766  		common.Log.Debug("BitsPerCoordinate not an integer (got %T)", obj)
   767  		return nil, ErrTypeError
   768  	}
   769  	shading.BitsPerCoordinate = integer
   770  
   771  	// BitsPerComponent (required).
   772  	obj = dict.Get("BitsPerComponent")
   773  	if obj == nil {
   774  		common.Log.Debug("Required attribute missing: BitsPerComponent")
   775  		return nil, ErrRequiredAttributeMissing
   776  	}
   777  	integer, ok = obj.(*PdfObjectInteger)
   778  	if !ok {
   779  		common.Log.Debug("BitsPerComponent not an integer (got %T)", obj)
   780  		return nil, ErrTypeError
   781  	}
   782  	shading.BitsPerComponent = integer
   783  
   784  	// BitsPerFlag (required).
   785  	obj = dict.Get("BitsPerFlag")
   786  	if obj == nil {
   787  		common.Log.Debug("Required attribute missing: BitsPerFlag")
   788  		return nil, ErrRequiredAttributeMissing
   789  	}
   790  	integer, ok = obj.(*PdfObjectInteger)
   791  	if !ok {
   792  		common.Log.Debug("BitsPerFlag not an integer (got %T)", obj)
   793  		return nil, ErrTypeError
   794  	}
   795  	shading.BitsPerComponent = integer
   796  
   797  	// Decode (required).
   798  	obj = dict.Get("Decode")
   799  	if obj == nil {
   800  		common.Log.Debug("Required attribute missing: Decode")
   801  		return nil, ErrRequiredAttributeMissing
   802  	}
   803  	arr, ok := obj.(*PdfObjectArray)
   804  	if !ok {
   805  		common.Log.Debug("Decode not an array (got %T)", obj)
   806  		return nil, ErrTypeError
   807  	}
   808  	shading.Decode = arr
   809  
   810  	// Function (optional).
   811  	if obj := dict.Get("Function"); obj != nil {
   812  		shading.Function = []PdfFunction{}
   813  		if array, is := obj.(*PdfObjectArray); is {
   814  			for _, obj := range *array {
   815  				function, err := newPdfFunctionFromPdfObject(obj)
   816  				if err != nil {
   817  					common.Log.Debug("Error parsing function: %v", err)
   818  					return nil, err
   819  				}
   820  				shading.Function = append(shading.Function, function)
   821  			}
   822  		} else {
   823  			function, err := newPdfFunctionFromPdfObject(obj)
   824  			if err != nil {
   825  				common.Log.Debug("Error parsing function: %v", err)
   826  				return nil, err
   827  			}
   828  			shading.Function = append(shading.Function, function)
   829  		}
   830  	}
   831  
   832  	return &shading, nil
   833  }
   834  
   835  /* Conversion to pdf objects. */
   836  
   837  func (this *PdfShading) ToPdfObject() PdfObject {
   838  	container := this.container
   839  
   840  	d, err := this.getShadingDict()
   841  	if err != nil {
   842  		common.Log.Error("Unable to access shading dict")
   843  		return nil
   844  	}
   845  
   846  	if this.ShadingType != nil {
   847  		d.Set("ShadingType", this.ShadingType)
   848  	}
   849  	if this.ColorSpace != nil {
   850  		d.Set("ColorSpace", this.ColorSpace.ToPdfObject())
   851  	}
   852  	if this.Background != nil {
   853  		d.Set("Background", this.Background)
   854  	}
   855  	if this.BBox != nil {
   856  		d.Set("BBox", this.BBox.ToPdfObject())
   857  	}
   858  	if this.AntiAlias != nil {
   859  		d.Set("AntiAlias", this.AntiAlias)
   860  	}
   861  
   862  	return container
   863  }
   864  
   865  func (this *PdfShadingType1) ToPdfObject() PdfObject {
   866  	this.PdfShading.ToPdfObject()
   867  
   868  	d, err := this.getShadingDict()
   869  	if err != nil {
   870  		common.Log.Error("Unable to access shading dict")
   871  		return nil
   872  	}
   873  
   874  	if this.Domain != nil {
   875  		d.Set("Domain", this.Domain)
   876  	}
   877  	if this.Matrix != nil {
   878  		d.Set("Matrix", this.Matrix)
   879  	}
   880  	if this.Function != nil {
   881  		if len(this.Function) == 1 {
   882  			d.Set("Function", this.Function[0].ToPdfObject())
   883  		} else {
   884  			farr := MakeArray()
   885  			for _, f := range this.Function {
   886  				farr.Append(f.ToPdfObject())
   887  			}
   888  			d.Set("Function", farr)
   889  		}
   890  	}
   891  
   892  	return this.container
   893  }
   894  
   895  func (this *PdfShadingType2) ToPdfObject() PdfObject {
   896  	this.PdfShading.ToPdfObject()
   897  
   898  	d, err := this.getShadingDict()
   899  	if err != nil {
   900  		common.Log.Error("Unable to access shading dict")
   901  		return nil
   902  	}
   903  	if d == nil {
   904  		common.Log.Error("Shading dict is nil")
   905  		return nil
   906  	}
   907  	if this.Coords != nil {
   908  		d.Set("Coords", this.Coords)
   909  	}
   910  	if this.Domain != nil {
   911  		d.Set("Domain", this.Domain)
   912  	}
   913  	if this.Function != nil {
   914  		if len(this.Function) == 1 {
   915  			d.Set("Function", this.Function[0].ToPdfObject())
   916  		} else {
   917  			farr := MakeArray()
   918  			for _, f := range this.Function {
   919  				farr.Append(f.ToPdfObject())
   920  			}
   921  			d.Set("Function", farr)
   922  		}
   923  	}
   924  	if this.Extend != nil {
   925  		d.Set("Extend", this.Extend)
   926  	}
   927  
   928  	return this.container
   929  }
   930  
   931  func (this *PdfShadingType3) ToPdfObject() PdfObject {
   932  	this.PdfShading.ToPdfObject()
   933  
   934  	d, err := this.getShadingDict()
   935  	if err != nil {
   936  		common.Log.Error("Unable to access shading dict")
   937  		return nil
   938  	}
   939  
   940  	if this.Coords != nil {
   941  		d.Set("Coords", this.Coords)
   942  	}
   943  	if this.Domain != nil {
   944  		d.Set("Domain", this.Domain)
   945  	}
   946  	if this.Function != nil {
   947  		if len(this.Function) == 1 {
   948  			d.Set("Function", this.Function[0].ToPdfObject())
   949  		} else {
   950  			farr := MakeArray()
   951  			for _, f := range this.Function {
   952  				farr.Append(f.ToPdfObject())
   953  			}
   954  			d.Set("Function", farr)
   955  		}
   956  	}
   957  	if this.Extend != nil {
   958  		d.Set("Extend", this.Extend)
   959  	}
   960  
   961  	return this.container
   962  }
   963  
   964  func (this *PdfShadingType4) ToPdfObject() PdfObject {
   965  	this.PdfShading.ToPdfObject()
   966  
   967  	d, err := this.getShadingDict()
   968  	if err != nil {
   969  		common.Log.Error("Unable to access shading dict")
   970  		return nil
   971  	}
   972  
   973  	if this.BitsPerCoordinate != nil {
   974  		d.Set("BitsPerCoordinate", this.BitsPerCoordinate)
   975  	}
   976  	if this.BitsPerComponent != nil {
   977  		d.Set("BitsPerComponent", this.BitsPerComponent)
   978  	}
   979  	if this.BitsPerFlag != nil {
   980  		d.Set("BitsPerFlag", this.BitsPerFlag)
   981  	}
   982  	if this.Decode != nil {
   983  		d.Set("Decode", this.Decode)
   984  	}
   985  	if this.Function != nil {
   986  		if len(this.Function) == 1 {
   987  			d.Set("Function", this.Function[0].ToPdfObject())
   988  		} else {
   989  			farr := MakeArray()
   990  			for _, f := range this.Function {
   991  				farr.Append(f.ToPdfObject())
   992  			}
   993  			d.Set("Function", farr)
   994  		}
   995  	}
   996  
   997  	return this.container
   998  }
   999  
  1000  func (this *PdfShadingType5) ToPdfObject() PdfObject {
  1001  	this.PdfShading.ToPdfObject()
  1002  
  1003  	d, err := this.getShadingDict()
  1004  	if err != nil {
  1005  		common.Log.Error("Unable to access shading dict")
  1006  		return nil
  1007  	}
  1008  
  1009  	if this.BitsPerCoordinate != nil {
  1010  		d.Set("BitsPerCoordinate", this.BitsPerCoordinate)
  1011  	}
  1012  	if this.BitsPerComponent != nil {
  1013  		d.Set("BitsPerComponent", this.BitsPerComponent)
  1014  	}
  1015  	if this.VerticesPerRow != nil {
  1016  		d.Set("VerticesPerRow", this.VerticesPerRow)
  1017  	}
  1018  	if this.Decode != nil {
  1019  		d.Set("Decode", this.Decode)
  1020  	}
  1021  	if this.Function != nil {
  1022  		if len(this.Function) == 1 {
  1023  			d.Set("Function", this.Function[0].ToPdfObject())
  1024  		} else {
  1025  			farr := MakeArray()
  1026  			for _, f := range this.Function {
  1027  				farr.Append(f.ToPdfObject())
  1028  			}
  1029  			d.Set("Function", farr)
  1030  		}
  1031  	}
  1032  
  1033  	return this.container
  1034  }
  1035  
  1036  func (this *PdfShadingType6) ToPdfObject() PdfObject {
  1037  	this.PdfShading.ToPdfObject()
  1038  
  1039  	d, err := this.getShadingDict()
  1040  	if err != nil {
  1041  		common.Log.Error("Unable to access shading dict")
  1042  		return nil
  1043  	}
  1044  
  1045  	if this.BitsPerCoordinate != nil {
  1046  		d.Set("BitsPerCoordinate", this.BitsPerCoordinate)
  1047  	}
  1048  	if this.BitsPerComponent != nil {
  1049  		d.Set("BitsPerComponent", this.BitsPerComponent)
  1050  	}
  1051  	if this.BitsPerFlag != nil {
  1052  		d.Set("BitsPerFlag", this.BitsPerFlag)
  1053  	}
  1054  	if this.Decode != nil {
  1055  		d.Set("Decode", this.Decode)
  1056  	}
  1057  	if this.Function != nil {
  1058  		if len(this.Function) == 1 {
  1059  			d.Set("Function", this.Function[0].ToPdfObject())
  1060  		} else {
  1061  			farr := MakeArray()
  1062  			for _, f := range this.Function {
  1063  				farr.Append(f.ToPdfObject())
  1064  			}
  1065  			d.Set("Function", farr)
  1066  		}
  1067  	}
  1068  
  1069  	return this.container
  1070  }
  1071  
  1072  func (this *PdfShadingType7) ToPdfObject() PdfObject {
  1073  	this.PdfShading.ToPdfObject()
  1074  
  1075  	d, err := this.getShadingDict()
  1076  	if err != nil {
  1077  		common.Log.Error("Unable to access shading dict")
  1078  		return nil
  1079  	}
  1080  
  1081  	if this.BitsPerCoordinate != nil {
  1082  		d.Set("BitsPerCoordinate", this.BitsPerCoordinate)
  1083  	}
  1084  	if this.BitsPerComponent != nil {
  1085  		d.Set("BitsPerComponent", this.BitsPerComponent)
  1086  	}
  1087  	if this.BitsPerFlag != nil {
  1088  		d.Set("BitsPerFlag", this.BitsPerFlag)
  1089  	}
  1090  	if this.Decode != nil {
  1091  		d.Set("Decode", this.Decode)
  1092  	}
  1093  	if this.Function != nil {
  1094  		if len(this.Function) == 1 {
  1095  			d.Set("Function", this.Function[0].ToPdfObject())
  1096  		} else {
  1097  			farr := MakeArray()
  1098  			for _, f := range this.Function {
  1099  				farr.Append(f.ToPdfObject())
  1100  			}
  1101  			d.Set("Function", farr)
  1102  		}
  1103  	}
  1104  
  1105  	return this.container
  1106  }