Changeset 317 for GraphicTest/BGRABitmap/bgrapaintnet.pas
- Timestamp:
- Feb 1, 2012, 3:02:33 PM (13 years ago)
- Location:
- GraphicTest/BGRABitmap
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest/BGRABitmap
-
Property svn:ignore
set to
lib
-
Property svn:ignore
set to
-
GraphicTest/BGRABitmap/bgrapaintnet.pas
r210 r317 5 5 interface 6 6 7 { This unit reads Paint.NET files. It needs BGRADNetDeserial to deserialize binary .Net objects. 8 9 A Paint.NET image consists in three parts : 10 - Xml header 11 - Binary serialized information (contains layer information) 12 - Compressed data (pixel data) 13 14 The class TPaintDotNetFile do not read the Xml header. ComputeFlatImage builds the resulting image 15 by using blending operations to merge layers. 16 17 The unit registers a TFPCustomImageReader so that it can be read by any image reading function of FreePascal } 18 7 19 uses 8 Classes, SysUtils, BGRADNetDeserial, BGRA Bitmap, BGRABitmapTypes;20 Classes, SysUtils, BGRADNetDeserial, BGRALayers, BGRABitmap, BGRABitmapTypes, FPImage; 9 21 10 22 type … … 12 24 { TPaintDotNetFile } 13 25 14 TPaintDotNetFile = class 26 TPaintDotNetFile = class(TBGRACustomLayeredBitmap) 15 27 public 16 procedure LoadFromFile(filename: string); 17 procedure LoadFromStream(stream: TStream); 18 procedure Clear; 19 function ToString: string;20 destructor Destroy; override;28 procedure LoadFromFile(filename: string); override; 29 procedure LoadFromStream(stream: TStream); override; 30 procedure Clear; override; 31 function ToString: ansistring; override; 32 function GetLayerBitmapCopy(layer: integer): TBGRABitmap; override; 21 33 constructor Create; 22 function Width: integer; 23 function Height: integer; 24 function NbLayers: integer; 25 function BlendOperation(Layer: integer): TBlendOperation; 26 function LayerVisible(layer: integer): boolean; 27 function LayerOpacity(layer: integer): byte; 28 function LayerName(layer: integer): string; 29 function MakeBitmapLayer(layer: integer): TBGRABitmap; 30 function ComputeFlatImage: TBGRABitmap; 34 protected 35 function GetWidth: integer; override; 36 function GetHeight: integer; override; 37 function GetNbLayers: integer; override; 38 function GetBlendOperation(Layer: integer): TBlendOperation; override; 39 function GetLayerVisible(layer: integer): boolean; override; 40 function GetLayerOpacity(layer: integer): byte; override; 41 function GetLayerName(layer: integer): string; override; 31 42 private 32 43 XmlHeader: string; 33 44 ThumbNail: TBGRABitmap; 34 45 Content: TDotNetDeserialization; 35 Document: PSerializedObject;36 Layers: PSerializedObject;46 Document: TSerializedClass; 47 Layers: TSerializedClass; 37 48 LayerData: array of TMemoryStream; 38 function GetLayer(num: integer): PSerializedObject;39 function GetBlendOperation(layer: PSerializedObject): TBlendOperation;40 function GetLayerName(layer: PSerializedObject): string;41 function GetLayerVisible(layer: PSerializedObject): boolean;42 function GetLayerOpacity(layer: PSerializedObject): byte;49 function InternalGetLayer(num: integer): TSerializedClass; 50 function InternalGetBlendOperation(layer: TSerializedClass): TBlendOperation; 51 function InternalGetLayerName(layer: TSerializedClass): string; 52 function InternalGetLayerVisible(layer: TSerializedClass): boolean; 53 function InternalGetLayerOpacity(layer: TSerializedClass): byte; 43 54 function LayerDataSize(numLayer: integer): int64; 44 55 procedure LoadLayer(dest: TMemoryStream; src: TStream; uncompressedSize: int64); 56 end; 57 58 { TFPReaderPaintDotNet } 59 60 TFPReaderPaintDotNet = class(TFPCustomImageReader) 61 protected 62 function InternalCheck(Stream: TStream): boolean; override; 63 procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override; 45 64 end; 46 65 … … 146 165 {$hints on} 147 166 167 { TFPReaderPaintDotNet } 168 169 function TFPReaderPaintDotNet.InternalCheck(Stream: TStream): boolean; 170 begin 171 result := IsPaintDotNetStream(stream); 172 end; 173 174 procedure TFPReaderPaintDotNet.InternalRead(Stream: TStream; Img: TFPCustomImage 175 ); 176 var 177 pdn: TPaintDotNetFile; 178 flat: TBGRABitmap; 179 x,y: integer; 180 begin 181 pdn := TPaintDotNetFile.Create; 182 try 183 pdn.LoadFromStream(Stream); 184 flat := pdn.ComputeFlatImage; 185 try 186 Img.SetSize(pdn.Width,pdn.Height); 187 for y := 0 to pdn.Height-1 do 188 for x := 0 to pdn.Width-1 do 189 Img.Colors[x,y] := BGRAToFPColor(flat.GetPixel(x,y)); 190 finally 191 flat.free; 192 end; 193 pdn.Free; 194 except 195 on ex: Exception do 196 begin 197 pdn.Free; 198 raise Exception.Create('Error while loading Paint.NET file. ' + ex.Message); 199 end; 200 end; 201 end; 202 148 203 { TPaintDotNetFile } 149 204 … … 163 218 var 164 219 header: packed array[0..3] of char; 165 XmlHeaderSize: longword;220 XmlHeaderSize: integer; 166 221 CompressionFormat: word; 167 222 i: integer; … … 192 247 IntToStr(Compressionformat) + ')'); 193 248 end; 194 Document := Content.Find Object('Document');249 Document := Content.FindClass('Document'); 195 250 if Document <> nil then 196 Layers := Content.GetObjectField(Document ^, 'layers');251 Layers := Content.GetObjectField(Document, 'layers') as TSerializedClass; 197 252 SetLength(LayerData, NbLayers); 198 253 for i := 0 to NbLayers - 1 do … … 203 258 end; 204 259 205 function TPaintDotNetFile.ToString: string;260 function TPaintDotNetFile.ToString: ansistring; 206 261 var 207 262 i, j, nbbytes: integer; … … 216 271 for i := 0 to NbLayers - 1 do 217 272 begin 218 Result += LineEnding + 'Layer ' + IntToStr(i) + ' : ' + LayerName (i)+ LineEnding;273 Result += LineEnding + 'Layer ' + IntToStr(i) + ' : ' + LayerName[i] + LineEnding; 219 274 Result += '[ '; 220 275 LayerData[i].Position := 0; … … 234 289 Result += ']' + lineending; 235 290 end; 236 end;237 238 destructor TPaintDotNetFile.Destroy;239 begin240 content.Free;241 Thumbnail.Free;242 inherited Destroy;243 291 end; 244 292 … … 265 313 end; 266 314 267 function TPaintDotNetFile. Width: integer;315 function TPaintDotNetFile.GetWidth: integer; 268 316 begin 269 317 if Document = nil then 270 318 Result := 0 271 319 else 272 Result := StrToInt(Content.GetSimpleField(Document ^, 'width'));273 end; 274 275 function TPaintDotNetFile. Height: integer;320 Result := StrToInt(Content.GetSimpleField(Document, 'width')); 321 end; 322 323 function TPaintDotNetFile.GetHeight: integer; 276 324 begin 277 325 if Document = nil then 278 326 Result := 0 279 327 else 280 Result := StrToInt(Content.GetSimpleField(Document ^, 'height'));281 end; 282 283 function TPaintDotNetFile. NbLayers: integer;328 Result := StrToInt(Content.GetSimpleField(Document, 'height')); 329 end; 330 331 function TPaintDotNetFile.GetNbLayers: integer; 284 332 begin 285 333 if Layers = nil then 286 334 Result := 0 287 335 else 288 Result := StrToInt(Content.GetSimpleField(Layers ^, '_size'));289 end; 290 291 function TPaintDotNetFile. BlendOperation(Layer: integer): TBlendOperation;292 begin 293 Result := GetBlendOperation(GetLayer(layer));294 end; 295 296 function TPaintDotNetFile. LayerVisible(layer: integer): boolean;297 begin 298 Result := GetLayerVisible(GetLayer(layer));299 end; 300 301 function TPaintDotNetFile. LayerOpacity(layer: integer): byte;302 begin 303 Result := GetLayerOpacity(GetLayer(layer));304 end; 305 306 function TPaintDotNetFile. LayerName(layer: integer): string;307 begin 308 Result := GetLayerName(GetLayer(layer));309 end; 310 311 function TPaintDotNetFile. MakeBitmapLayer(layer: integer): TBGRABitmap;336 Result := StrToInt(Content.GetSimpleField(Layers, '_size')); 337 end; 338 339 function TPaintDotNetFile.GetBlendOperation(Layer: integer): TBlendOperation; 340 begin 341 Result := InternalGetBlendOperation(InternalGetLayer(layer)); 342 end; 343 344 function TPaintDotNetFile.GetLayerVisible(layer: integer): boolean; 345 begin 346 Result := InternalGetLayerVisible(InternalGetLayer(layer)); 347 end; 348 349 function TPaintDotNetFile.GetLayerOpacity(layer: integer): byte; 350 begin 351 Result := InternalGetLayerOpacity(InternalGetLayer(layer)); 352 end; 353 354 function TPaintDotNetFile.GetLayerName(layer: integer): string; 355 begin 356 Result := InternalGetLayerName(InternalGetLayer(layer)); 357 end; 358 359 function TPaintDotNetFile.GetLayerBitmapCopy(layer: integer): TBGRABitmap; 312 360 begin 313 361 if (layer < 0) or (layer >= NbLayers) then … … 315 363 316 364 Result := TBGRABitmap.Create(Width, Height); 317 if Result.NbPixels* 4 <> LayerData[layer].Size then365 if int64(Result.NbPixels) * 4 <> LayerData[layer].Size then 318 366 begin 319 367 Result.Free; … … 331 379 end; 332 380 333 function TPaintDotNetFile.ComputeFlatImage: TBGRABitmap; 334 var 335 tempLayer, tempMerge: TBGRABitmap; 336 i: integer; 337 begin 338 Result := TBGRABitmap.Create(Width, Height); 339 for i := 0 to NbLayers - 1 do 340 begin 341 tempLayer := MakeBitmapLayer(i); 342 if tempLayer <> nil then 343 begin 344 //first layer is simply the background 345 if i = 0 then 346 Result.PutImage(0, 0, tempLayer, dmSet) 347 else 348 //simple blend operations 349 if BlendOperation(i) in [boTransparent, boLinearBlend] then 350 begin 351 tempLayer.ApplyGlobalOpacity(LayerOpacity(i)); 352 Result.BlendImage(0, 0, tempLayer, BlendOperation(i)); 353 end 354 else 355 //complex blend operations are done in a third bitmap 356 begin 357 tempMerge := Result.Duplicate as TBGRABitmap; 358 tempMerge.BlendImage(0, 0, tempLayer, BlendOperation(i)); 359 tempMerge.ApplyGlobalOpacity(LayerOpacity(i)); 360 Result.PutImage(0, 0, tempMerge, dmFastBlend); 361 tempMerge.Free; 362 end; 363 tempLayer.Free; 364 end; 365 end; 366 end; 367 368 function TPaintDotNetFile.GetLayerName(layer: PSerializedObject): string; 369 var 370 prop: PSerializedObject; 381 function TPaintDotNetFile.InternalGetLayerName(layer: TSerializedClass): string; 382 var 383 prop: TCustomSerializedObject; 371 384 begin 372 385 if layer = nil then … … 374 387 else 375 388 begin 376 prop := Content.GetObjectField(layer ^, 'Layer+properties');389 prop := Content.GetObjectField(layer, 'Layer+properties'); 377 390 if prop = nil then 378 391 Result := '' 379 392 else 380 393 begin 381 Result := Content.GetSimpleField(prop ^, 'name');394 Result := Content.GetSimpleField(prop, 'name'); 382 395 end; 383 396 end; … … 386 399 function TPaintDotNetFile.LayerDataSize(numLayer: integer): int64; 387 400 var 388 layer, surface, scan0: PSerializedObject;389 begin 390 layer := GetLayer(numLayer);401 layer, surface, scan0: TCustomSerializedObject; 402 begin 403 layer := InternalGetLayer(numLayer); 391 404 if layer = nil then 392 405 Result := 0 393 406 else 394 407 begin 395 surface := Content.GetObjectField(layer ^, 'surface');408 surface := Content.GetObjectField(layer, 'surface'); 396 409 if surface = nil then 397 410 Result := 0 398 411 else 399 412 begin 400 scan0 := Content.GetObjectField(surface ^, 'scan0');401 Result := StrToInt64(Content.GetSimpleField(scan0 ^, 'length64'));413 scan0 := Content.GetObjectField(surface, 'scan0'); 414 Result := StrToInt64(Content.GetSimpleField(scan0, 'length64')); 402 415 end; 403 416 end; … … 457 470 end; 458 471 459 function TPaintDotNetFile. GetLayer(num: integer): PSerializedObject;460 var 461 layerList: PSerializedObject;472 function TPaintDotNetFile.InternalGetLayer(num: integer): TSerializedClass; 473 var 474 layerList: TCustomSerializedObject; 462 475 begin 463 476 if Layers = nil then … … 468 481 else 469 482 begin 470 layerList := Content.GetObjectField(Layers ^, '_items');471 Result := Content.GetObject(layerList ^.fields[num].Value);472 end; 473 end; 474 475 function TPaintDotNetFile. GetBlendOperation(layer: PSerializedObject): TBlendOperation;476 var 477 prop, blendOp: PSerializedObject;483 layerList := Content.GetObjectField(Layers, '_items'); 484 Result := Content.GetObject(layerList.FieldAsString[num]) as TSerializedClass; 485 end; 486 end; 487 488 function TPaintDotNetFile.InternalGetBlendOperation(layer: TSerializedClass): TBlendOperation; 489 var 490 prop, blendOp: TCustomSerializedObject; 478 491 blendName: string; 479 492 begin … … 482 495 else 483 496 begin 484 prop := Content.GetObjectField(layer ^, 'properties');497 prop := Content.GetObjectField(layer, 'properties'); 485 498 if prop = nil then 486 499 Result := boTransparent 487 500 else 488 501 begin 489 blendOp := Content.GetObjectField(prop ^, 'blendOp');502 blendOp := Content.GetObjectField(prop, 'blendOp'); 490 503 if blendOp = nil then 491 504 Result := boTransparent 492 505 else 493 506 begin 494 blendName := Content.GetObjectType(blendOp);507 blendName := blendOp.TypeAsString; 495 508 if (pos('+', blendName) <> 0) then 496 509 Delete(blendName, 1, pos('+', blendName)); … … 548 561 end; 549 562 550 function TPaintDotNetFile. GetLayerVisible(layer: PSerializedObject): boolean;551 var 552 prop: PSerializedObject;563 function TPaintDotNetFile.InternalGetLayerVisible(layer: TSerializedClass): boolean; 564 var 565 prop: TCustomSerializedObject; 553 566 begin 554 567 if layer = nil then … … 556 569 else 557 570 begin 558 prop := Content.GetObjectField(layer ^, 'Layer+properties');571 prop := Content.GetObjectField(layer, 'Layer+properties'); 559 572 if prop = nil then 560 573 Result := False 561 574 else 562 575 begin 563 Result := (Content.GetSimpleField(prop ^, 'visible') = 'True');564 end; 565 end; 566 end; 567 568 function TPaintDotNetFile. GetLayerOpacity(layer: PSerializedObject): byte;569 var 570 prop: PSerializedObject;576 Result := (Content.GetSimpleField(prop, 'visible') = 'True'); 577 end; 578 end; 579 end; 580 581 function TPaintDotNetFile.InternalGetLayerOpacity(layer: TSerializedClass): byte; 582 var 583 prop: TCustomSerializedObject; 571 584 begin 572 585 if layer = nil then … … 574 587 else 575 588 begin 576 prop := Content.GetObjectField(layer ^, 'Layer+properties');589 prop := Content.GetObjectField(layer, 'Layer+properties'); 577 590 if prop = nil then 578 591 Result := 0 579 592 else 580 593 begin 581 Result := StrToInt(Content.GetSimpleField(prop^, 'opacity')); 582 end; 583 end; 584 end; 585 586 {var fout: TFileStream; 587 comp: Tcompressionstream; 588 589 gzipHeader: packed record 590 magicWord: word; 591 compMethod,flags: byte; 592 fileModif: Longword; 593 extraflag,os: byte; 594 end; } 594 Result := StrToInt(Content.GetSimpleField(prop, 'opacity')); 595 end; 596 end; 597 end; 595 598 596 599 initialization 597 600 598 { gzipHeader.magicWord := $8b1F; 599 gzipHeader.compMethod := 8; 600 gzipHeader.flags := 0; 601 gzipHeader.fileModif := 0; 602 gzipHeader.extraflag := 0; 603 gzipHeader.os := $ff; 604 605 fout := TFileStream.Create('testcomp.gz', fmCreate); 606 fout.Write(gzipHeader,sizeof(gzipHeader)); 607 comp := Tcompressionstream.Create(cldefault,fout,true); 608 comp.WriteAnsiString('Hello world'); 609 comp.free; 610 fout.Free; } 601 ImageHandlers.RegisterImageReader ('Paint.NET image', 'pdn', TFPReaderPaintDotNet); 611 602 612 603 end. 613 604 605
Note:
See TracChangeset
for help on using the changeset viewer.