Color.st
changeset 8123 099bb6b94798
parent 8112 0825f3c6a0cb
child 8125 4deac40e67b0
equal deleted inserted replaced
8122:24692d82a3d5 8123:099bb6b94798
    14 "{ NameSpace: Smalltalk }"
    14 "{ NameSpace: Smalltalk }"
    15 
    15 
    16 Object subclass:#Color
    16 Object subclass:#Color
    17 	instanceVariableNames:'red green blue device colorId ditherForm replacementColor
    17 	instanceVariableNames:'red green blue device colorId ditherForm replacementColor
    18 		writable'
    18 		writable'
    19 	classVariableNames:'MaxValue Cells Black White LightGrey Grey DarkGrey Pseudo0
    19 	classVariableNames:'Black Blue Cells ColorAllocationFailSignal ColorErrorSignal
    20 		Pseudo1 PseudoAll Red Green Blue Yellow Orange RetryAllocation
    20 		DarkGrey DitherBits Green Grey InvalidColorNameSignal LightGrey
    21 		DitherBits ColorErrorSignal ColorAllocationFailSignal
    21 		MaxValue Orange Pseudo0 Pseudo1 PseudoAll Red RetryAllocation
    22 		InvalidColorNameSignal StandardColorValues Transparent'
    22 		StandardColorValues Transparent White Yellow'
    23 	poolDictionaries:''
    23 	poolDictionaries:''
    24 	category:'Graphics-Support'
    24 	category:'Graphics-Support'
    25 !
    25 !
    26 
    26 
    27 Object subclass:#DeviceColorHandle
    27 Object subclass:#DeviceColorHandle
   161         Claus Gittinger
   161         Claus Gittinger
   162 "
   162 "
   163 ! !
   163 ! !
   164 
   164 
   165 !Color class methodsFor:'initialization'!
   165 !Color class methodsFor:'initialization'!
   166 
       
   167 allocateColorsIn:aColorVector on:aDevice
       
   168     "{ Pragma: +optSpace }"
       
   169 
       
   170     "preallocates a nR x nG x nB colorMap for later use in dithering.
       
   171      Doing so has the advantage that the system will never run out of colors,
       
   172      however, colors may be either inexact or dithered."
       
   173 
       
   174     |clr round devClr|
       
   175 
       
   176     round := 0.
       
   177     1 to:aColorVector size do:[:dstIndex |
       
   178         clr := aColorVector at:dstIndex.
       
   179         devClr := clr exactOn:aDevice.
       
   180         devClr isNil ifTrue:[
       
   181             round == 0 ifTrue:[
       
   182                 Logger info:'scavenge to reclaim colors'.
       
   183                 ObjectMemory scavenge.
       
   184                 round := 1.
       
   185                 devClr := clr exactOn:aDevice.
       
   186             ].
       
   187             devClr isNil ifTrue:[
       
   188                 round == 1 ifTrue:[
       
   189                     Logger info:'collect garbage to reclaim colors'.
       
   190                     ObjectMemory 
       
   191                         garbageCollect; finalize.
       
   192                     round := 2.
       
   193                     devClr := clr exactOn:aDevice.
       
   194                 ].
       
   195                 devClr isNil ifTrue:[
       
   196                     round == 2 ifTrue:[
       
   197                         Logger info:'lowSpaceCleanup and collect garbage to reclaim colors'.
       
   198                         ObjectMemory 
       
   199                             performLowSpaceCleanup;
       
   200                             garbageCollect; finalize.
       
   201                         round := 3.
       
   202                         devClr := clr exactOn:aDevice.
       
   203                     ].
       
   204                     devClr isNil ifTrue:[
       
   205                         ColorAllocationFailSignal raiseErrorString:'failed to allocate fix color'.
       
   206                         ^ self
       
   207                     ].
       
   208                 ].
       
   209             ].
       
   210         ].
       
   211         aColorVector at:dstIndex put:devClr.
       
   212     ].
       
   213 
       
   214     "Modified: / 02-03-2017 / 17:43:36 / stefan"
       
   215 !
       
   216 
       
   217 colorCubeWithRed:nRed green:nGreen blue:nBlue
       
   218     "{ Pragma: +optSpace }"
       
   219 
       
   220     |nR "{Class: SmallInteger }"
       
   221      nG "{Class: SmallInteger }"
       
   222      nB "{Class: SmallInteger }"
       
   223      dR dG dB red green blue dstIndex clr round
       
   224      colorCube|
       
   225 
       
   226     nR := nRed.
       
   227     nG := nGreen.
       
   228     nB := nBlue.
       
   229 
       
   230     dR := 100.0 / (nR - 1).
       
   231     dG := 100.0 / (nG - 1).
       
   232     dB := 100.0 / (nB - 1).
       
   233 
       
   234     colorCube := Array new:(nR * nG * nB).
       
   235 
       
   236     round := 0.
       
   237 
       
   238     dstIndex := 1.
       
   239     1 to:nR do:[:sR |
       
   240 	red := dR * (sR - 1).
       
   241 	1 to:nG do:[:sG |
       
   242 	    green := dG * (sG - 1).
       
   243 	    1 to:nB do:[:sB |
       
   244 		blue := dB * (sB - 1).
       
   245 		clr := self red:red green:green blue:blue.
       
   246 		colorCube at:dstIndex put:clr.
       
   247 		dstIndex := dstIndex + 1
       
   248 	    ]
       
   249 	]
       
   250     ].
       
   251     ^ colorCube
       
   252 
       
   253     "Created: 11.7.1996 / 17:55:32 / cg"
       
   254     "Modified: 10.1.1997 / 15:37:13 / cg"
       
   255 !
       
   256 
       
   257 flushDeviceColors
       
   258     "unassign all colors from their device"
       
   259 
       
   260     self allInstances do:[:aColor |
       
   261 	aColor restored
       
   262     ].
       
   263 
       
   264     "Modified: 24.2.1997 / 18:27:06 / cg"
       
   265 !
       
   266 
       
   267 flushDeviceColorsFor:aDevice
       
   268     self allInstancesDo:[:aColor |
       
   269 	aColor device == aDevice ifTrue:[
       
   270 	    aColor restored
       
   271 	]
       
   272     ]
       
   273 !
       
   274 
       
   275 getColors6x6x4
       
   276     "{ Pragma: +optSpace }"
       
   277 
       
   278     "preallocates a 6x6x4 (144) colorMap and later uses those colors only.
       
   279      Doing so has the advantage that the system will never run out of colors,
       
   280      however, colors may be either inexact or dithered."
       
   281 
       
   282     self getColorsRed:6 green:6 blue:4
       
   283 
       
   284     "
       
   285      Color getColors6x6x4
       
   286     "
       
   287 !
       
   288 
       
   289 getColors6x6x5
       
   290     "{ Pragma: +optSpace }"
       
   291 
       
   292     "preallocates a 6x6x5 (180) colorMap and later uses those colors only.
       
   293      Doing so has the advantage that the system will never run out of colors,
       
   294      however, colors may be either inexact or dithered."
       
   295 
       
   296     self getColorsRed:6 green:6 blue:5
       
   297 
       
   298     "
       
   299      Color getColors6x6x5
       
   300     "
       
   301 !
       
   302 
       
   303 getColors6x6x6
       
   304     "{ Pragma: +optSpace }"
       
   305 
       
   306     "preallocates a 6x6x6 (196) colorMap and later uses those colors only.
       
   307      Doing so has the advantage that the system will never run out of colors,
       
   308      however, colors may be either inexact or dithered."
       
   309 
       
   310     self getColorsRed:6 green:6 blue:6
       
   311 
       
   312     "
       
   313      Color getColors6x6x6
       
   314     "
       
   315 !
       
   316 
       
   317 getColors6x7x4
       
   318     "{ Pragma: +optSpace }"
       
   319 
       
   320     "preallocates a 6x7x4 (168) colorMap and later uses those colors only.
       
   321      Doing so has the advantage that the system will never run out of colors,
       
   322      however, colors may be either inexact or dithered."
       
   323 
       
   324     self getColorsRed:6 green:7 blue:4
       
   325 
       
   326     "
       
   327      Color getColors6x7x4
       
   328     "
       
   329 
       
   330     "Created: 12.6.1996 / 17:41:57 / cg"
       
   331 !
       
   332 
       
   333 getColors7x8x4
       
   334     "{ Pragma: +optSpace }"
       
   335 
       
   336     "preallocates a 7x8x4 (224) colorMap and later uses those colors only.
       
   337      Doing so has the advantage that the system will never run out of colors,
       
   338      however, colors may be either inexact or dithered."
       
   339 
       
   340     self getColorsRed:7 green:8 blue:4
       
   341 
       
   342     "
       
   343      Color getColors7x8x4
       
   344     "
       
   345 !
       
   346 
       
   347 getColorsRed:nRed green:nGreen blue:nBlue
       
   348     "{ Pragma: +optSpace }"
       
   349 
       
   350     "preallocates a nR x nG x nB colorMap for later use in dithering.
       
   351      Doing so has the advantage that the system will never run out of colors,
       
   352      however, colors may be either inexact or dithered."
       
   353 
       
   354     self getColorsRed:nRed green:nGreen blue:nBlue on:Screen current
       
   355 
       
   356     "
       
   357      Color getColorsRed:2 green:2 blue:2
       
   358     "
       
   359 
       
   360     "Modified: 11.7.1996 / 17:58:09 / cg"
       
   361 !
       
   362 
       
   363 getColorsRed:nRed green:nGreen blue:nBlue on:aDevice
       
   364     "{ Pragma: +optSpace }"
       
   365 
       
   366     "preallocates a nR x nG x nB colorMap for later use in dithering.
       
   367      Doing so has the advantage that the system will never run out of colors,
       
   368      however, colors may be either inexact or dithered."
       
   369 
       
   370     |nR "{Class: SmallInteger }"
       
   371      nG "{Class: SmallInteger }"
       
   372      nB "{Class: SmallInteger }"
       
   373      dR dG dB fixColors|
       
   374 
       
   375     aDevice visualType == #TrueColor ifTrue:[^ self].
       
   376 
       
   377     nR := nRed.
       
   378     nG := nGreen.
       
   379     nB := nBlue.
       
   380 
       
   381     dR := 100.0 / (nR - 1).
       
   382     dG := 100.0 / (nG - 1).
       
   383     dB := 100.0 / (nB - 1).
       
   384 
       
   385     fixColors := self colorCubeWithRed:nRed green:nGreen blue:nBlue.
       
   386     self allocateColorsIn:fixColors on:aDevice.
       
   387 
       
   388     aDevice setFixColors:fixColors numRed:nR numGreen:nG numBlue:nB
       
   389 
       
   390     "
       
   391      Color getColorsRed:2 green:2 blue:2 on:Display
       
   392     "
       
   393 
       
   394     "Created: 11.7.1996 / 17:55:32 / cg"
       
   395     "Modified: 10.1.1997 / 15:37:13 / cg"
       
   396 !
       
   397 
       
   398 getGrayColors:nGray on:aDevice
       
   399     "{ Pragma: +optSpace }"
       
   400 
       
   401     "preallocates nGray gray colors for later use in dithering.
       
   402      Doing so has the advantage that the system will never run out of colors,
       
   403      however, colors may be either inexact or dithered."
       
   404 
       
   405     |nG "{Class: SmallInteger }"
       
   406      d fixGrayColors|
       
   407 
       
   408     aDevice visualType == #TrueColor ifTrue:[^ self].
       
   409 
       
   410     nG := nGray.
       
   411     d := 100.0 / (nG - 1).
       
   412 
       
   413     fixGrayColors := self grayColorVector:nGray.
       
   414     self allocateColorsIn:fixGrayColors on:aDevice.
       
   415 
       
   416     aDevice setFixGrayColors:fixGrayColors
       
   417 
       
   418     "
       
   419      Color getGrayColors:16 on:Display
       
   420     "
       
   421 
       
   422     "Created: 23.6.1997 / 15:29:50 / cg"
       
   423 !
       
   424 
       
   425 getPrimaryColorsOn:aDevice
       
   426     "{ Pragma: +optSpace }"
       
   427 
       
   428     "preallocate the primary colors.
       
   429      Doing so during early startup prevents us from running out
       
   430      of (at least those required) colors later.
       
   431      This guarantees, that at least some colors are available
       
   432      for dithering (although, with only black, white, red, green and blue,
       
   433      dithered images look very poor)."
       
   434 
       
   435     |colors white black red green blue clr dDepth
       
   436      lastPix "{ Class: SmallInteger }" |
       
   437 
       
   438     (aDevice notNil and:[aDevice ditherColors isNil]) ifTrue:[
       
   439 	white := (self red:100 green:100 blue:100) exactOn:aDevice.
       
   440 	white colorId isNil ifTrue:[
       
   441 	    'Color [warning]: cannot allocate white color' errorPrintCR.
       
   442 	].
       
   443 	black := (self red:0 green:0 blue:0) exactOn:aDevice.
       
   444 	black colorId isNil ifTrue:[
       
   445 	    'Color [warning]: cannot allocate black color' errorPrintCR.
       
   446 	].
       
   447 
       
   448 	aDevice hasColors ifTrue:[
       
   449 	    red := (self red:100 green:0 blue:0) exactOn:aDevice.
       
   450 	    green := (self red:0 green:100 blue:0) exactOn:aDevice.
       
   451 	    blue := (self red:0 green:0 blue:100) exactOn:aDevice.
       
   452 	    (red isNil
       
   453 	    or:[green isNil
       
   454 	    or:[blue isNil
       
   455 	    or:[red colorId isNil
       
   456 	    or:[green colorId isNil
       
   457 	    or:[blue colorId isNil]]]]]) ifTrue:[
       
   458 		'Color [warning]: cannot allocate primary color(s)' errorPrintCR.
       
   459 		dDepth := aDevice depth.
       
   460 		((dDepth >= 4) and:[dDepth <= 8]) ifTrue:[
       
   461 		    "/
       
   462 		    "/ see what we have ...
       
   463 		    "/
       
   464 		    lastPix := (1 bitShift:dDepth) - 1.
       
   465 		    0 to:lastPix do:[:pixel |
       
   466 			colors := OrderedCollection new.
       
   467 			aDevice getRGBFrom:pixel into:[:r :g :b |
       
   468 			    colors add:((Color red:r green:g blue:b) exactOn:aDevice).
       
   469 			]
       
   470 		    ].
       
   471 		    red := (self red:100 green:0 blue:0) nearestOn:aDevice.
       
   472 		    green := (self red:0 green:100 blue:0) nearestOn:aDevice.
       
   473 		    blue := (self red:0 green:0 blue:100) nearestOn:aDevice.
       
   474 		] ifFalse:[
       
   475 		    aDevice hasColors:false.
       
   476 		    aDevice hasGrayscales:false.
       
   477 		    red := green := blue := nil.
       
   478 		]
       
   479 	    ]
       
   480 	].
       
   481 
       
   482 	aDevice == Display ifTrue:[
       
   483 	    "/ keep those around for the main display
       
   484 	    White := white.
       
   485 	    Black := black.
       
   486 	    Red := red.
       
   487 	    Green := green.
       
   488 	    Blue := blue
       
   489 	].
       
   490 
       
   491 	aDevice visualType ~~ #TrueColor ifTrue:[
       
   492 	    aDevice hasColors ifTrue:[
       
   493 
       
   494 		"preallocate some colors for dithering
       
   495 		 - otherwise, they may not be available when we need them ...
       
   496 		 these are: black, white, grey50,
       
   497 			    red, green, blue, yellow, cyan and magenta.
       
   498 		"
       
   499 
       
   500 		colors := OrderedCollection new.
       
   501 		clr := (self gray:50) exactOn:aDevice.
       
   502 		(clr notNil and:[clr colorId notNil]) ifTrue:[
       
   503 		    colors add:clr
       
   504 		].
       
   505 
       
   506 		colors add:white; add:black; add:red; add:green; add:blue.
       
   507 
       
   508 		colors add:((self red:100 green:100 blue:0) exactOn:aDevice).
       
   509 		colors add:((self red:100 green:0 blue:100) exactOn:aDevice).
       
   510 		colors add:((self red:0 green:100 blue:100) exactOn:aDevice).
       
   511 	    ].
       
   512 
       
   513 	    aDevice hasGrayscales ifTrue:[
       
   514 		aDevice hasColors ifFalse:[
       
   515 		    colors := OrderedCollection new.
       
   516 		    colors add:((self gray:50) exactOn:aDevice).
       
   517 		    colors add:white; add:black.
       
   518 
       
   519 		].
       
   520 		colors add:((self gray:25) exactOn:aDevice).
       
   521 		colors add:((self gray:33) exactOn:aDevice).
       
   522 		colors add:((self gray:67) exactOn:aDevice).
       
   523 		colors add:((self gray:75) exactOn:aDevice).
       
   524 	    ].
       
   525 
       
   526 	    colors notNil ifTrue:[
       
   527 		colors := colors select:[:clr | clr notNil and:[clr colorId notNil]].
       
   528 		aDevice setDitherColors:(colors asArray).
       
   529 	    ]
       
   530 	]
       
   531     ]
       
   532 
       
   533     "Created: 11.7.1996 / 18:09:28 / cg"
       
   534     "Modified: 21.10.1997 / 02:42:28 / cg"
       
   535 !
       
   536 
       
   537 grayColorVector:nGray
       
   538     |nG "{Class: SmallInteger }"
       
   539      d gray dstIndex clr round
       
   540      grayColors|
       
   541 
       
   542     nG := nGray.
       
   543     d := 100.0 / (nG - 1).
       
   544 
       
   545     grayColors := Array new:nG.
       
   546 
       
   547     round := 0.
       
   548 
       
   549     dstIndex := 1.
       
   550     1 to:nG do:[:sG |
       
   551 	gray := d * (sG - 1).
       
   552 	clr := self red:gray green:gray blue:gray.
       
   553 	grayColors at:dstIndex put:clr.
       
   554 	dstIndex := dstIndex + 1
       
   555     ].
       
   556     ^ grayColors
       
   557 
       
   558     "
       
   559      Color getGrayColors:16 on:Display
       
   560     "
       
   561 
       
   562     "Created: 23.6.1997 / 15:29:50 / cg"
       
   563 !
       
   564 
   166 
   565 initialize
   167 initialize
   566     "setup tracker of known colors and initialize classvars with
   168     "setup tracker of known colors and initialize classvars with
   567      heavily used colors"
   169      heavily used colors"
   568 
   170 
   627     "
   229     "
   628 
   230 
   629     "Modified: 6.3.1997 / 02:28:58 / cg"
   231     "Modified: 6.3.1997 / 02:28:58 / cg"
   630 !
   232 !
   631 
   233 
   632 standardDitherColorsForDepth8
       
   633     "return a set of colors useful for dithering (roughly 200 colors);
       
   634      This includes a color cube and the main grayScale colors."
       
   635 
       
   636     |ditherColors|
       
   637 
       
   638     ditherColors := self colorCubeWithRed:6 green:8 blue:4.
       
   639     ditherColors := ditherColors ,
       
   640 		    (Array
       
   641 			with:(Color gray:20)
       
   642 			with:(Color gray:25)
       
   643 			with:(Color gray:40)
       
   644 			with:(Color gray:50)
       
   645 			with:(Color gray:60)
       
   646 			with:(Color gray:75)
       
   647 			with:(Color gray:80)
       
   648 			with:(Color rgbValue:16rBFBFBF)).
       
   649     ^ ditherColors
       
   650 
       
   651     "
       
   652      self standardDitherColorsForDepth8
       
   653     "
       
   654 !
       
   655 
       
   656 update:something with:aParameter from:changedObject
   234 update:something with:aParameter from:changedObject
   657     "handle image restarts and flush any device resource handles"
   235     "handle image restarts and flush any device resource handles"
   658 
   236 
   659     (something == #returnFromSnapshot) ifTrue:[
   237     (something == #returnFromSnapshot) ifTrue:[
   660 	Display notNil ifTrue:[
   238 	Display notNil ifTrue:[
   681 	]
   259 	]
   682     ]
   260     ]
   683 
   261 
   684     "Created: 15.6.1996 / 15:14:03 / cg"
   262     "Created: 15.6.1996 / 15:14:03 / cg"
   685     "Modified: 24.2.1997 / 22:08:05 / cg"
   263     "Modified: 24.2.1997 / 22:08:05 / cg"
   686 !
       
   687 
       
   688 vgaColors
       
   689     "{ Pragma: +optSpace }"
       
   690 
       
   691     |colors|
       
   692 
       
   693     colors := Array new:16.
       
   694     colors at:1 put:(Color rgbValue:16rFFFFFF).
       
   695     colors at:2 put:(Color rgbValue:16rC0C0C0).
       
   696     colors at:3 put:(Color rgbValue:16r808080).
       
   697     colors at:4 put:(Color rgbValue:16r000000).
       
   698     colors at:5 put:(Color rgbValue:16rFF0000).
       
   699     colors at:6 put:(Color rgbValue:16r800000).
       
   700     colors at:7 put:(Color rgbValue:16r008000).
       
   701     colors at:8 put:(Color rgbValue:16r00FF00).
       
   702     colors at:9 put:(Color rgbValue:16r0000FF).
       
   703     colors at:10 put:(Color rgbValue:16r000080).
       
   704     colors at:11 put:(Color rgbValue:16rFF00FF).
       
   705     colors at:12 put:(Color rgbValue:16r800080).
       
   706     colors at:13 put:(Color rgbValue:16rFFFF00).
       
   707     colors at:14 put:(Color rgbValue:16r808000).
       
   708     colors at:15 put:(Color rgbValue:16r00FFFF).
       
   709     colors at:16 put:(Color rgbValue:16r008080).
       
   710     ^ colors
       
   711 
       
   712     "Created: / 07-07-2006 / 13:36:15 / cg"
       
   713 ! !
   264 ! !
   714 
   265 
   715 !Color class methodsFor:'instance creation'!
   266 !Color class methodsFor:'instance creation'!
   716 
   267 
   717 allColor
   268 allColor
  3942 
  3493 
  3943     "Created: 14.6.1996 / 20:13:22 / cg"
  3494     "Created: 14.6.1996 / 20:13:22 / cg"
  3944     "Modified: 11.7.1996 / 18:20:14 / cg"
  3495     "Modified: 11.7.1996 / 18:20:14 / cg"
  3945 ! !
  3496 ! !
  3946 
  3497 
       
  3498 !Color class methodsFor:'utilities'!
       
  3499 
       
  3500 allocateColorsIn:aColorVector on:aDevice
       
  3501     "{ Pragma: +optSpace }"
       
  3502 
       
  3503     "preallocates a nR x nG x nB colorMap for later use in dithering.
       
  3504      Doing so has the advantage that the system will never run out of colors,
       
  3505      however, colors may be either inexact or dithered."
       
  3506 
       
  3507     |clr round devClr|
       
  3508 
       
  3509     round := 0.
       
  3510     1 to:aColorVector size do:[:dstIndex |
       
  3511         clr := aColorVector at:dstIndex.
       
  3512         devClr := clr exactOn:aDevice.
       
  3513         devClr isNil ifTrue:[
       
  3514             round == 0 ifTrue:[
       
  3515                 Logger info:'scavenge to reclaim colors'.
       
  3516                 ObjectMemory scavenge.
       
  3517                 round := 1.
       
  3518                 devClr := clr exactOn:aDevice.
       
  3519             ].
       
  3520             devClr isNil ifTrue:[
       
  3521                 round == 1 ifTrue:[
       
  3522                     Logger info:'collect garbage to reclaim colors'.
       
  3523                     ObjectMemory 
       
  3524                         garbageCollect; finalize.
       
  3525                     round := 2.
       
  3526                     devClr := clr exactOn:aDevice.
       
  3527                 ].
       
  3528                 devClr isNil ifTrue:[
       
  3529                     round == 2 ifTrue:[
       
  3530                         Logger info:'lowSpaceCleanup and collect garbage to reclaim colors'.
       
  3531                         ObjectMemory 
       
  3532                             performLowSpaceCleanup;
       
  3533                             garbageCollect; finalize.
       
  3534                         round := 3.
       
  3535                         devClr := clr exactOn:aDevice.
       
  3536                     ].
       
  3537                     devClr isNil ifTrue:[
       
  3538                         ColorAllocationFailSignal raiseErrorString:'failed to allocate fix color'.
       
  3539                         ^ self
       
  3540                     ].
       
  3541                 ].
       
  3542             ].
       
  3543         ].
       
  3544         aColorVector at:dstIndex put:devClr.
       
  3545     ].
       
  3546 
       
  3547     "Modified: / 02-03-2017 / 17:43:36 / stefan"
       
  3548 !
       
  3549 
       
  3550 best:numColors ditherColorsForImage:anImage 
       
  3551     "work in progress"
       
  3552     
       
  3553     |bigCube boxMax numBits numGray usedColors 
       
  3554      minRed maxRed minGreen maxGreen minBlue maxBlue
       
  3555      boundaryColors boxesSegmented segments boxesToDo enumerateNeighbors
       
  3556      firstTry segmentColors|
       
  3557 
       
  3558     ((anImage photometric == #blackIs0) or:[anImage photometric == #whiteIs0]) ifTrue:[
       
  3559         numGray := (1 bitShift:anImage depth) min:numColors. 
       
  3560         ^ self grayColorVector:numGray
       
  3561     ].    
       
  3562     (anImage photometric == #palette) ifTrue:[
       
  3563         "/ all gray?
       
  3564         (anImage colorMap conform:[:clr | clr isGrayColor]) ifTrue:[
       
  3565             numGray := ((1 bitShift:anImage depth) min:anImage colorMap size) min:numColors. 
       
  3566             ^ self grayColorVector:numGray
       
  3567         ].    
       
  3568     ].    
       
  3569 
       
  3570     boxMax := 63.
       
  3571     numBits := 6.
       
  3572     firstTry := true.
       
  3573 
       
  3574     [
       
  3575         "/ first, a rough cube with less precision...
       
  3576         bigCube := IntegerArray new:(boxMax+1)*(boxMax+1)*(boxMax+1).
       
  3577 
       
  3578         firstTry ifTrue:[
       
  3579             usedColors := Set new.
       
  3580             minRed := minGreen := minBlue := 255.
       
  3581             maxRed := maxGreen := maxBlue := 0.
       
  3582         ].
       
  3583         
       
  3584         anImage 
       
  3585             rgbValuesFromX:0 y:0 
       
  3586             toX:(anImage width-1) y:(anImage height-1)
       
  3587             do:[:x :y :rgb |
       
  3588                 |redByte greenByte blueByte r g b idx oldCount|
       
  3589 
       
  3590                 redByte := (rgb rightShift:16) bitAnd:16rFF.
       
  3591                 greenByte := (rgb rightShift:8) bitAnd:16rFF.
       
  3592                 blueByte := (rgb) bitAnd:16rFF.
       
  3593 
       
  3594                 r := redByte rightShift:(8-numBits).
       
  3595                 g := greenByte rightShift:(8-numBits).
       
  3596                 b := blueByte rightShift:(8-numBits).
       
  3597                 idx := (((r * (boxMax+1))+g)*(boxMax+1))+b+1.
       
  3598                 oldCount := bigCube at:idx.
       
  3599 
       
  3600                 firstTry ifTrue:[
       
  3601                     redByte < minRed ifTrue:[minRed := redByte] ifFalse:[redByte > maxRed ifTrue:[maxRed := redByte]].
       
  3602                     greenByte < minGreen ifTrue:[minGreen := greenByte] ifFalse:[greenByte > maxGreen ifTrue:[maxGreen := greenByte]].
       
  3603                     blueByte < minBlue ifTrue:[minBlue := blueByte] ifFalse:[blueByte > maxBlue ifTrue:[maxBlue := blueByte]].
       
  3604 
       
  3605                     oldCount == 0 ifTrue:[
       
  3606                         usedColors add:rgb.
       
  3607                     ].    
       
  3608                 ].    
       
  3609                 bigCube at:idx put:oldCount+1.
       
  3610             ].    
       
  3611 
       
  3612         firstTry ifTrue:[
       
  3613             usedColors size <= numColors ifTrue:[
       
  3614                 "/ huh - that will be easy!!
       
  3615                 ^ usedColors asArray.
       
  3616             ].
       
  3617 
       
  3618             "/ if not even the basic colors fit, dither to b&w
       
  3619             numColors == 2 ifTrue:[
       
  3620                 ^ { Color black . Color white }
       
  3621             ].
       
  3622             "/ if not even the basic colors fit, dither to b&w
       
  3623             numColors == 4 ifTrue:[
       
  3624                 ^ { Color black . Color red . Color green . Color blue. }
       
  3625             ].
       
  3626 
       
  3627             "/ we need the at least the 8 corners for dithering, at least...
       
  3628             boundaryColors := OrderedCollection new.
       
  3629             { minRed . maxRed } do:[:r |
       
  3630                 { minGreen . maxGreen } do:[:g |
       
  3631                     { minBlue . maxBlue } do:[:b |
       
  3632                         boundaryColors add:(Color redByte:r greenByte:g blueByte:b)
       
  3633                     ].
       
  3634                 ].
       
  3635             ].
       
  3636             numColors == 8 ifTrue:[
       
  3637                 ^ boundaryColors
       
  3638             ].
       
  3639         ].
       
  3640         firstTry := false.
       
  3641         
       
  3642         "/
       
  3643         "/ find and generate connected subarea box sets
       
  3644         "/
       
  3645         boxesSegmented := Set new.
       
  3646         segments := OrderedCollection new.    
       
  3647 
       
  3648         boxesToDo := OrderedCollection new.
       
  3649 
       
  3650         "/ each box has 9+9+3+3+1+1 neighbors
       
  3651         "/ 
       
  3652         enumerateNeighbors :=
       
  3653             [:rgb :aBlock|
       
  3654                 |r g b|
       
  3655 
       
  3656                 r := (rgb rightShift:(numBits+numBits)) bitAnd:boxMax.
       
  3657                 g := (rgb rightShift:numBits) bitAnd:boxMax.
       
  3658                 b := (rgb) bitAnd:boxMax.
       
  3659                 r-1 to:r+1 do:[:n_r |
       
  3660                     (n_r between:0 and:boxMax) ifTrue:[
       
  3661                         g-1 to:g+1 do:[:n_g |
       
  3662                             (n_g between:0 and:boxMax) ifTrue:[
       
  3663                                 b-1 to:b+1 do:[:n_b |
       
  3664                                     (n_b between:0 and:boxMax) ifTrue:[
       
  3665                                         ((n_r == r) and:[n_g == g and:[n_b == b]]) ifFalse:[
       
  3666                                             aBlock value:((((n_r * (boxMax+1))+n_g)*(boxMax+1))+n_b).
       
  3667                                         ]
       
  3668                                     ]
       
  3669                                 ]
       
  3670                             ]
       
  3671                         ]
       
  3672                     ]
       
  3673                 ].
       
  3674             ].
       
  3675 
       
  3676         0 to:boxMax do:[:r |
       
  3677             0 to:boxMax do:[:g |
       
  3678                 0 to:boxMax do:[:b |
       
  3679                     |rgb|
       
  3680 
       
  3681                     rgb := (((r * (boxMax+1))+g)*(boxMax+1))+b.
       
  3682                     (bigCube at:rgb+1) ~~ 0 ifTrue:[
       
  3683                         (boxesSegmented includes:rgb) ifFalse:[
       
  3684                             |currentSegment|
       
  3685 
       
  3686                             "/ start a segment
       
  3687                             currentSegment := OrderedCollection new.
       
  3688                             segments add:currentSegment.
       
  3689 
       
  3690                             boxesToDo add:rgb.
       
  3691                             boxesSegmented add:rgb.
       
  3692 
       
  3693                             [boxesToDo notEmpty] whileTrue:[
       
  3694                                 |rgb|
       
  3695 
       
  3696                                 rgb := boxesToDo removeLast.
       
  3697                                 currentSegment add:rgb.
       
  3698 
       
  3699                                 enumerateNeighbors value:rgb value:[:n_rgb |
       
  3700                                     (bigCube at:n_rgb+1) ~~ 0 ifTrue:[
       
  3701                                         "/ neighbor has used pixels as well...
       
  3702                                         (boxesSegmented includes:n_rgb) ifFalse:[
       
  3703                                             "/ neighbor was not processed...
       
  3704                                             boxesSegmented add:rgb.
       
  3705                                             boxesToDo add:n_rgb.
       
  3706                                         ].
       
  3707                                     ].    
       
  3708                                 ].
       
  3709                             ].
       
  3710                         ].    
       
  3711                     ].    
       
  3712                 ]
       
  3713             ]
       
  3714         ].
       
  3715         
       
  3716         (segments size < numColors) ifTrue:[
       
  3717             segmentColors := segments 
       
  3718                                 collect:[:eachSegment |
       
  3719                                     |n sumRed sumGreen sumBlue centerRed centerGreen centerBlue|
       
  3720                                     
       
  3721                                     "/ compute central point
       
  3722                                     "/ as center of mass (taking count per box as weight)
       
  3723                                     "/ this central point will be placed into the colormap.
       
  3724                                     sumRed := sumGreen := sumBlue := 0.
       
  3725                                     n := eachSegment size.
       
  3726                                     
       
  3727                                     eachSegment do:[:rgbOfBoxInSegment |
       
  3728                                         |r g b|
       
  3729                                         
       
  3730                                         r := (rgbOfBoxInSegment rightShift:(numBits+numBits)) bitAnd:boxMax.
       
  3731                                         g := (rgbOfBoxInSegment rightShift:numBits) bitAnd:boxMax.
       
  3732                                         b := (rgbOfBoxInSegment) bitAnd:boxMax.
       
  3733                                         sumRed :=sumRed + r.
       
  3734                                         sumGreen := sumGreen + g.
       
  3735                                         sumBlue := sumBlue + b.
       
  3736                                     ].
       
  3737                                     centerRed := (sumRed / n) rounded.
       
  3738                                     centerGreen := (sumGreen / n) rounded.
       
  3739                                     centerBlue := (sumBlue / n) rounded.
       
  3740 
       
  3741                                     centerRed := (centerRed bitShift:(8-numBits))
       
  3742                                                  bitOr:(centerRed bitShift:(8-numBits-numBits)). 
       
  3743                                     centerGreen := (centerGreen bitShift:(8-numBits))
       
  3744                                                  bitOr:(centerGreen bitShift:(8-numBits-numBits)). 
       
  3745                                     centerBlue := (centerBlue bitShift:(8-numBits))
       
  3746                                                  bitOr:(centerBlue bitShift:(8-numBits-numBits)). 
       
  3747                                     
       
  3748                                     Color redByte:centerRed greenByte:centerGreen blueByte:centerBlue.
       
  3749                                 ]
       
  3750                                 as:OrderedCollection.
       
  3751             "/ can we add black & white?
       
  3752             (segmentColors includes:Color white) ifFalse:[
       
  3753                 segmentColors add:Color white.
       
  3754             ].    
       
  3755             (segmentColors includes:Color black) ifFalse:[
       
  3756                 segmentColors add:Color black.
       
  3757             ].    
       
  3758             "/ can we add the boundary colors?
       
  3759             boundaryColors do:[:each |
       
  3760                 (segmentColors size < numColors) ifTrue:[
       
  3761                     (segmentColors includes:each) ifFalse:[
       
  3762                         segmentColors add:each.
       
  3763                     ].    
       
  3764                 ].
       
  3765             ].
       
  3766             ^ segmentColors.
       
  3767         ].
       
  3768         
       
  3769         numBits := numBits - 1.
       
  3770         boxMax := ((boxMax+1) // 2) - 1.
       
  3771         
       
  3772         numBits == 0 ifTrue:[
       
  3773             self error.
       
  3774         ].    
       
  3775     ] loop.
       
  3776     
       
  3777     "
       
  3778      Color
       
  3779         best:16 
       
  3780         ditherColorsForImage:(Image fromFile:'../../goodies/bitmaps/pcxImages/lena_depth8_palette.pcx')
       
  3781 
       
  3782      Color
       
  3783         best:16 
       
  3784         ditherColorsForImage:(Image fromFile:'../../goodies/bitmaps/pcxImages/lena_depth24_rgb.pcx')
       
  3785 
       
  3786      Color
       
  3787         best:16 
       
  3788         ditherColorsForImage:((Image fromFile:'../../goodies/bitmaps/pcxImages/lena_depth8_palette.pcx') asGrayImageDepth:8)
       
  3789 
       
  3790     "
       
  3791 
       
  3792     "Created: / 29-08-2017 / 14:31:19 / cg"
       
  3793     "Modified (comment): / 29-08-2017 / 20:00:32 / cg"
       
  3794 !
       
  3795 
       
  3796 browserColors
       
  3797     "return the palette, known as 'the color cube', 'the Netscape palette',
       
  3798      or 'the Browser-Safe palette'.
       
  3799      This is familiar to all seasoned Web designers and graphics production specialists;
       
  3800      Use this map for low-color-res depth 8 (gif-) images, if old pseudo displays are to be
       
  3801      supported."
       
  3802      
       
  3803     ^ self colorCubeWithRed:6 green:6 blue:6.
       
  3804 
       
  3805     "
       
  3806      |img|
       
  3807 
       
  3808      img := Image width:(8*6*6)+1 height:(8*6)+1 depth:8.
       
  3809      img colorMap:(Color browserColors). 
       
  3810      img pixelFunction:
       
  3811          [:x :y |
       
  3812             |r g b|
       
  3813             
       
  3814             (y \\ 8 == 0 ) ifTrue:[
       
  3815                 86
       
  3816             ] ifFalse:[
       
  3817                 x \\ 8 == 0 ifTrue:[
       
  3818                     86
       
  3819                 ] ifFalse:[
       
  3820                     r := g := b := 0.
       
  3821                     'y is green component'.
       
  3822                     g := 5-(y // 8).
       
  3823                     'x inside subsquare is blue component'.
       
  3824                     b := (x \\ (8*6)) // 8.
       
  3825                     'subsquare is red component'.
       
  3826                     r := (x // (8*6)).
       
  3827                     ((r*6)+g)*6+b
       
  3828                 ]
       
  3829             ].    
       
  3830          ].
       
  3831      img inspect. 
       
  3832     "
       
  3833 
       
  3834     "Created: / 29-08-2017 / 17:01:23 / cg"
       
  3835 !
       
  3836 
       
  3837 colorCubeWithRed:nRed green:nGreen blue:nBlue
       
  3838     "given a number of red, green and blue shades,
       
  3839      return a color cube (map) containing those colors.
       
  3840      Eg, return a map containing any combination of the
       
  3841      nRed, nGreen and nBlue shades.
       
  3842      This is used for dithering of deep images onto limited-depth canvases
       
  3843      for example: with nRed,nGreen,nBlue == 2,3,2
       
  3844       you will get a cube of 2*3*2 = 12 colors, with two shades of red (0 and 255),
       
  3845       threed shades of green (0, 127 and 255) and two shades of blue (0 and 255)."
       
  3846     
       
  3847     "{ Pragma: +optSpace }"
       
  3848 
       
  3849     |nR "{Class: SmallInteger }"
       
  3850      nG "{Class: SmallInteger }"
       
  3851      nB "{Class: SmallInteger }"
       
  3852      dR dG dB red green blue dstIndex clr round
       
  3853      colorCube|
       
  3854 
       
  3855     nR := nRed.
       
  3856     nG := nGreen.
       
  3857     nB := nBlue.
       
  3858 
       
  3859     dR := 100.0 / (nR - 1).
       
  3860     dG := 100.0 / (nG - 1).
       
  3861     dB := 100.0 / (nB - 1).
       
  3862 
       
  3863     colorCube := Array new:(nR * nG * nB).
       
  3864 
       
  3865     round := 0.
       
  3866 
       
  3867     dstIndex := 1.
       
  3868     1 to:nR do:[:sR |
       
  3869         red := dR * (sR - 1).
       
  3870         1 to:nG do:[:sG |
       
  3871             green := dG * (sG - 1).
       
  3872             1 to:nB do:[:sB |
       
  3873                 blue := dB * (sB - 1).
       
  3874                 clr := self red:red green:green blue:blue.
       
  3875                 colorCube at:dstIndex put:clr.
       
  3876                 dstIndex := dstIndex + 1
       
  3877             ]
       
  3878         ]
       
  3879     ].
       
  3880     ^ colorCube
       
  3881 
       
  3882     "
       
  3883      Color colorCubeWithRed:2 green:2 blue:2
       
  3884      Color colorCubeWithRed:2 green:3 blue:2
       
  3885      Color colorCubeWithRed:3 green:4 blue:3
       
  3886     "
       
  3887 
       
  3888     "Created: / 11-07-1996 / 17:55:32 / cg"
       
  3889     "Modified: / 10-01-1997 / 15:37:13 / cg"
       
  3890     "Modified (comment): / 29-08-2017 / 14:27:58 / cg"
       
  3891 !
       
  3892 
       
  3893 flushDeviceColors
       
  3894     "unassign all colors from their device"
       
  3895 
       
  3896     self allInstances do:[:aColor |
       
  3897 	aColor restored
       
  3898     ].
       
  3899 
       
  3900     "Modified: 24.2.1997 / 18:27:06 / cg"
       
  3901 !
       
  3902 
       
  3903 flushDeviceColorsFor:aDevice
       
  3904     self allInstancesDo:[:aColor |
       
  3905 	aColor device == aDevice ifTrue:[
       
  3906 	    aColor restored
       
  3907 	]
       
  3908     ]
       
  3909 !
       
  3910 
       
  3911 getColors6x6x4
       
  3912     "{ Pragma: +optSpace }"
       
  3913 
       
  3914     "preallocates a 6x6x4 (144) colorMap and later uses those colors only
       
  3915      on a palette display (pseudoColor visual).
       
  3916 
       
  3917      Doing so has the advantage that the system will never run out of colors,
       
  3918      however, colors may be either inexact or dithered."
       
  3919 
       
  3920     self getColorsRed:6 green:6 blue:4
       
  3921 
       
  3922     "
       
  3923      Color getColors6x6x4
       
  3924     "
       
  3925 
       
  3926     "Modified (comment): / 29-08-2017 / 17:22:22 / cg"
       
  3927 !
       
  3928 
       
  3929 getColors6x6x5
       
  3930     "{ Pragma: +optSpace }"
       
  3931 
       
  3932     "preallocates a 6x6x5 (180) colorMap and later uses those colors only
       
  3933      on a palette display (pseudoColor visual).
       
  3934 
       
  3935      Doing so has the advantage that the system will never run out of colors,
       
  3936      however, colors may be either inexact or dithered."
       
  3937 
       
  3938     self getColorsRed:6 green:6 blue:5
       
  3939 
       
  3940     "
       
  3941      Color getColors6x6x5
       
  3942     "
       
  3943 
       
  3944     "Modified (comment): / 29-08-2017 / 17:22:17 / cg"
       
  3945 !
       
  3946 
       
  3947 getColors6x6x6
       
  3948     "{ Pragma: +optSpace }"
       
  3949 
       
  3950     "preallocates a 6x6x6 (196) colorMap and later uses those colors only
       
  3951      on a palette display (pseudoColor visual).
       
  3952 
       
  3953      Doing so has the advantage that the system will never run out of colors,
       
  3954      however, colors may be either inexact or dithered."
       
  3955 
       
  3956     self getColorsRed:6 green:6 blue:6
       
  3957 
       
  3958     "
       
  3959      Color getColors6x6x6
       
  3960     "
       
  3961 
       
  3962     "Modified (comment): / 29-08-2017 / 17:22:10 / cg"
       
  3963 !
       
  3964 
       
  3965 getColors6x7x4
       
  3966     "{ Pragma: +optSpace }"
       
  3967 
       
  3968     "preallocates a 6x7x4 (168) colorMap and later uses those colors only
       
  3969      on a palette display (pseudoColor visual).
       
  3970 
       
  3971      Doing so has the advantage that the system will never run out of colors,
       
  3972      however, colors may be either inexact or dithered."
       
  3973 
       
  3974     self getColorsRed:6 green:7 blue:4
       
  3975 
       
  3976     "
       
  3977      Color getColors6x7x4
       
  3978     "
       
  3979 
       
  3980     "Created: / 12-06-1996 / 17:41:57 / cg"
       
  3981     "Modified (comment): / 29-08-2017 / 17:22:04 / cg"
       
  3982 !
       
  3983 
       
  3984 getColors7x8x4
       
  3985     "{ Pragma: +optSpace }"
       
  3986 
       
  3987     "preallocates a 7x8x4 (224) colorMap and later uses those colors only
       
  3988      on a palette display (pseudoColor visual).
       
  3989      
       
  3990      Doing so has the advantage that the system will never run out of colors,
       
  3991      however, colors may be either inexact or dithered."
       
  3992 
       
  3993     self getColorsRed:7 green:8 blue:4
       
  3994 
       
  3995     "
       
  3996      Color getColors7x8x4
       
  3997     "
       
  3998 
       
  3999     "Modified (comment): / 29-08-2017 / 17:21:56 / cg"
       
  4000 !
       
  4001 
       
  4002 getColorsRed:nRed green:nGreen blue:nBlue
       
  4003     "{ Pragma: +optSpace }"
       
  4004 
       
  4005     "preallocates a nR x nG x nB colorMap for later use in dithering
       
  4006      on a palette display (pseudoColor visual).
       
  4007      
       
  4008      Doing so has the advantage that the system will never run out of colors,
       
  4009      however, colors may be either inexact or dithered."
       
  4010 
       
  4011     self getColorsRed:nRed green:nGreen blue:nBlue on:Screen current
       
  4012 
       
  4013     "
       
  4014      Color getColorsRed:2 green:2 blue:2
       
  4015     "
       
  4016 
       
  4017     "Modified: / 11-07-1996 / 17:58:09 / cg"
       
  4018     "Modified (comment): / 29-08-2017 / 16:47:34 / cg"
       
  4019 !
       
  4020 
       
  4021 getColorsRed:nRed green:nGreen blue:nBlue on:aDevice
       
  4022     "{ Pragma: +optSpace }"
       
  4023 
       
  4024     "preallocates a nR x nG x nB colorMap for later use in dithering
       
  4025      on a palette display (pseudoColor visual).
       
  4026      
       
  4027      Doing so has the advantage that the system will never run out of colors,
       
  4028      however, colors may be either inexact or dithered."
       
  4029 
       
  4030     |nR "{Class: SmallInteger }"
       
  4031      nG "{Class: SmallInteger }"
       
  4032      nB "{Class: SmallInteger }"
       
  4033      dR dG dB fixColors|
       
  4034 
       
  4035     aDevice visualType == #TrueColor ifTrue:[^ self].
       
  4036 
       
  4037     nR := nRed.
       
  4038     nG := nGreen.
       
  4039     nB := nBlue.
       
  4040 
       
  4041     dR := 100.0 / (nR - 1).
       
  4042     dG := 100.0 / (nG - 1).
       
  4043     dB := 100.0 / (nB - 1).
       
  4044 
       
  4045     fixColors := self colorCubeWithRed:nRed green:nGreen blue:nBlue.
       
  4046     self allocateColorsIn:fixColors on:aDevice.
       
  4047 
       
  4048     aDevice setFixColors:fixColors numRed:nR numGreen:nG numBlue:nB
       
  4049 
       
  4050     "
       
  4051      Color getColorsRed:2 green:2 blue:2 on:Display
       
  4052     "
       
  4053 
       
  4054     "Created: / 11-07-1996 / 17:55:32 / cg"
       
  4055     "Modified: / 10-01-1997 / 15:37:13 / cg"
       
  4056     "Modified (comment): / 29-08-2017 / 16:47:38 / cg"
       
  4057 !
       
  4058 
       
  4059 getGrayColors:nGray on:aDevice
       
  4060     "{ Pragma: +optSpace }"
       
  4061 
       
  4062     "preallocates nGray gray colors for later use in dithering
       
  4063      on a palette display (pseudoColor visual).
       
  4064 
       
  4065      Doing so has the advantage that the system will never run out of colors,
       
  4066      however, colors may be either inexact or dithered."
       
  4067 
       
  4068     |nG "{Class: SmallInteger }"
       
  4069      d fixGrayColors|
       
  4070 
       
  4071     aDevice visualType == #TrueColor ifTrue:[^ self].
       
  4072 
       
  4073     nG := nGray.
       
  4074     d := 100.0 / (nG - 1).
       
  4075 
       
  4076     fixGrayColors := self grayColorVector:nGray.
       
  4077     self allocateColorsIn:fixGrayColors on:aDevice.
       
  4078 
       
  4079     aDevice setFixGrayColors:fixGrayColors
       
  4080 
       
  4081     "
       
  4082      Color getGrayColors:16 on:Display
       
  4083     "
       
  4084 
       
  4085     "Created: / 23-06-1997 / 15:29:50 / cg"
       
  4086     "Modified (comment): / 29-08-2017 / 17:23:18 / cg"
       
  4087 !
       
  4088 
       
  4089 getPrimaryColorsOn:aDevice
       
  4090     "{ Pragma: +optSpace }"
       
  4091 
       
  4092     "preallocate the primary colors on a palette display (pseudoColor visual).
       
  4093 
       
  4094      Doing so during early startup prevents us from running out
       
  4095      of (at least those required) colors later.
       
  4096      This guarantees, that at least some colors are available
       
  4097      for dithering (although, with only black, white, red, green and blue,
       
  4098      dithered images look very poor)."
       
  4099 
       
  4100     |colors white black red green blue clr dDepth
       
  4101      lastPix "{ Class: SmallInteger }" |
       
  4102 
       
  4103     (aDevice notNil and:[aDevice ditherColors isNil]) ifTrue:[
       
  4104         white := (self red:100 green:100 blue:100) exactOn:aDevice.
       
  4105         white colorId isNil ifTrue:[
       
  4106             'Color [warning]: cannot allocate white color' errorPrintCR.
       
  4107         ].
       
  4108         black := (self red:0 green:0 blue:0) exactOn:aDevice.
       
  4109         black colorId isNil ifTrue:[
       
  4110             'Color [warning]: cannot allocate black color' errorPrintCR.
       
  4111         ].
       
  4112 
       
  4113         aDevice hasColors ifTrue:[
       
  4114             red := (self red:100 green:0 blue:0) exactOn:aDevice.
       
  4115             green := (self red:0 green:100 blue:0) exactOn:aDevice.
       
  4116             blue := (self red:0 green:0 blue:100) exactOn:aDevice.
       
  4117             (red isNil
       
  4118             or:[green isNil
       
  4119             or:[blue isNil
       
  4120             or:[red colorId isNil
       
  4121             or:[green colorId isNil
       
  4122             or:[blue colorId isNil]]]]]) ifTrue:[
       
  4123                 'Color [warning]: cannot allocate primary color(s)' errorPrintCR.
       
  4124                 dDepth := aDevice depth.
       
  4125                 ((dDepth >= 4) and:[dDepth <= 8]) ifTrue:[
       
  4126                     "/
       
  4127                     "/ see what we have ...
       
  4128                     "/
       
  4129                     lastPix := (1 bitShift:dDepth) - 1.
       
  4130                     0 to:lastPix do:[:pixel |
       
  4131                         colors := OrderedCollection new.
       
  4132                         aDevice getRGBFrom:pixel into:[:r :g :b |
       
  4133                             colors add:((Color red:r green:g blue:b) exactOn:aDevice).
       
  4134                         ]
       
  4135                     ].
       
  4136                     red := (self red:100 green:0 blue:0) nearestOn:aDevice.
       
  4137                     green := (self red:0 green:100 blue:0) nearestOn:aDevice.
       
  4138                     blue := (self red:0 green:0 blue:100) nearestOn:aDevice.
       
  4139                 ] ifFalse:[
       
  4140                     aDevice hasColors:false.
       
  4141                     aDevice hasGrayscales:false.
       
  4142                     red := green := blue := nil.
       
  4143                 ]
       
  4144             ]
       
  4145         ].
       
  4146 
       
  4147         aDevice == Display ifTrue:[
       
  4148             "/ keep those around for the main display
       
  4149             White := white.
       
  4150             Black := black.
       
  4151             Red := red.
       
  4152             Green := green.
       
  4153             Blue := blue
       
  4154         ].
       
  4155 
       
  4156         aDevice visualType ~~ #TrueColor ifTrue:[
       
  4157             aDevice hasColors ifTrue:[
       
  4158 
       
  4159                 "preallocate some colors for dithering
       
  4160                  - otherwise, they may not be available when we need them ...
       
  4161                  these are: black, white, grey50,
       
  4162                             red, green, blue, yellow, cyan and magenta.
       
  4163                 "
       
  4164 
       
  4165                 colors := OrderedCollection new.
       
  4166                 clr := (self gray:50) exactOn:aDevice.
       
  4167                 (clr notNil and:[clr colorId notNil]) ifTrue:[
       
  4168                     colors add:clr
       
  4169                 ].
       
  4170 
       
  4171                 colors add:white; add:black; add:red; add:green; add:blue.
       
  4172 
       
  4173                 colors add:((self red:100 green:100 blue:0) exactOn:aDevice).
       
  4174                 colors add:((self red:100 green:0 blue:100) exactOn:aDevice).
       
  4175                 colors add:((self red:0 green:100 blue:100) exactOn:aDevice).
       
  4176             ].
       
  4177 
       
  4178             aDevice hasGrayscales ifTrue:[
       
  4179                 aDevice hasColors ifFalse:[
       
  4180                     colors := OrderedCollection new.
       
  4181                     colors add:((self gray:50) exactOn:aDevice).
       
  4182                     colors add:white; add:black.
       
  4183 
       
  4184                 ].
       
  4185                 colors add:((self gray:25) exactOn:aDevice).
       
  4186                 colors add:((self gray:33) exactOn:aDevice).
       
  4187                 colors add:((self gray:67) exactOn:aDevice).
       
  4188                 colors add:((self gray:75) exactOn:aDevice).
       
  4189             ].
       
  4190 
       
  4191             colors notNil ifTrue:[
       
  4192                 colors := colors select:[:clr | clr notNil and:[clr colorId notNil]].
       
  4193                 aDevice setDitherColors:(colors asArray).
       
  4194             ]
       
  4195         ]
       
  4196     ]
       
  4197 
       
  4198     "Created: / 11-07-1996 / 18:09:28 / cg"
       
  4199     "Modified: / 21-10-1997 / 02:42:28 / cg"
       
  4200     "Modified (comment): / 29-08-2017 / 17:23:36 / cg"
       
  4201 !
       
  4202 
       
  4203 grayColorVector:nGray
       
  4204     |nG "{Class: SmallInteger }"
       
  4205      d gray dstIndex clr round
       
  4206      grayColors|
       
  4207 
       
  4208     nG := nGray.
       
  4209     d := 100.0 / (nG - 1).
       
  4210 
       
  4211     grayColors := Array new:nG.
       
  4212 
       
  4213     round := 0.
       
  4214 
       
  4215     dstIndex := 1.
       
  4216     1 to:nG do:[:sG |
       
  4217 	gray := d * (sG - 1).
       
  4218 	clr := self red:gray green:gray blue:gray.
       
  4219 	grayColors at:dstIndex put:clr.
       
  4220 	dstIndex := dstIndex + 1
       
  4221     ].
       
  4222     ^ grayColors
       
  4223 
       
  4224     "
       
  4225      Color getGrayColors:16 on:Display
       
  4226     "
       
  4227 
       
  4228     "Created: 23.6.1997 / 15:29:50 / cg"
       
  4229 !
       
  4230 
       
  4231 standardDitherColorsForDepth8
       
  4232     "return a set of colors useful for dithering (roughly 200 colors);
       
  4233      This includes a color cube and the main grayScale colors."
       
  4234 
       
  4235     |ditherColors|
       
  4236 
       
  4237     ditherColors := self colorCubeWithRed:6 green:8 blue:4.
       
  4238     ditherColors := ditherColors ,
       
  4239                         ( #(10 20 25 30 40 50 60 70 75 80 90) 
       
  4240                             collect:[:grayPercent | Color gray:grayPercent]
       
  4241                             thenSelect:[:grey | (ditherColors includes:grey) not] )
       
  4242                         asArray.    
       
  4243     ^ ditherColors
       
  4244 
       
  4245     "
       
  4246      self standardDitherColorsForDepth8
       
  4247     "
       
  4248 
       
  4249     "Modified: / 29-08-2017 / 17:29:58 / cg"
       
  4250 !
       
  4251 
       
  4252 vgaColors
       
  4253     "{ Pragma: +optSpace }"
       
  4254 
       
  4255     |colors|
       
  4256 
       
  4257     colors := Array new:16.
       
  4258     colors at:1 put:(Color rgbValue:16rFFFFFF).
       
  4259     colors at:2 put:(Color rgbValue:16rC0C0C0).
       
  4260     colors at:3 put:(Color rgbValue:16r808080).
       
  4261     colors at:4 put:(Color rgbValue:16r000000).
       
  4262     colors at:5 put:(Color rgbValue:16rFF0000).
       
  4263     colors at:6 put:(Color rgbValue:16r800000).
       
  4264     colors at:7 put:(Color rgbValue:16r008000).
       
  4265     colors at:8 put:(Color rgbValue:16r00FF00).
       
  4266     colors at:9 put:(Color rgbValue:16r0000FF).
       
  4267     colors at:10 put:(Color rgbValue:16r000080).
       
  4268     colors at:11 put:(Color rgbValue:16rFF00FF).
       
  4269     colors at:12 put:(Color rgbValue:16r800080).
       
  4270     colors at:13 put:(Color rgbValue:16rFFFF00).
       
  4271     colors at:14 put:(Color rgbValue:16r808000).
       
  4272     colors at:15 put:(Color rgbValue:16r00FFFF).
       
  4273     colors at:16 put:(Color rgbValue:16r008080).
       
  4274     ^ colors
       
  4275 
       
  4276     "Created: / 07-07-2006 / 13:36:15 / cg"
       
  4277 ! !
       
  4278 
  3947 !Color methodsFor:'Compatibility-ST80'!
  4279 !Color methodsFor:'Compatibility-ST80'!
  3948 
  4280 
  3949 asDevicePaintOn:aDevice
  4281 asDevicePaintOn:aDevice
  3950     "ST-80 compatibility: an alias for on:.
  4282     "ST-80 compatibility: an alias for on:.
  3951      create a new Color representing the same color as
  4283      create a new Color representing the same color as