2012-04-30 17 views
9

मेरा आवेदन उनके साथ काम करने का प्रयास करते हुए PNG का का एक बहुत है और मैं अक्सर गंदगी मेरी कोड की जरूरत है। मेरे जीवन को आसान बनाने के लिए मैंने रीयलवर्ड पेंट में एक बड़ी पीएनजी छवि बनाई और उन सभी छोटी पीएनजी छवियों को चिपकाया। अब मेरे पास एक फाइल है। अब मुझे केवल एक पीएनजी को पारदर्शीता के साथ कॉपी करना है (बीटीडब्ल्यू क्यों नहीं पूछें), क्योंकि मुझे प्रत्येक छवि के साथ काम करने की ज़रूरत है। जब छवियों के साथ काम करने की बात आती है तो मैं खराब प्रोग्रामर हूं। मैं डेल्फी 7.अन्य पीएनजी से एक पीएनजी कैसे कॉपी करें?

PGNImage.Resize

procedure TPngObject.Resize(const CX, CY: Integer); 
    function Min(const A, B: Integer): Integer; 
    begin 
    if A < B then Result := A else Result := B; 
    end; 
var 
    Header: TChunkIHDR; 
    Line, NewBytesPerRow: Integer; 
    NewHandle: HBitmap; 
    NewDC: HDC; 
    NewImageData: Pointer; 
    NewImageAlpha: Pointer; 
    NewImageExtra: Pointer; 
begin 
    if (CX > 0) and (CY > 0) then 
    begin 
    {Gets some actual information} 
    Header := Self.Header; 

    {Creates the new image} 
    NewDC := CreateCompatibleDC(Header.ImageDC); 
    Header.BitmapInfo.bmiHeader.biWidth := cx; 
    Header.BitmapInfo.bmiHeader.biHeight := cy; 
    NewHandle := CreateDIBSection(NewDC, pBitmapInfo(@Header.BitmapInfo)^, 
     DIB_RGB_COLORS, NewImageData, 0, 0); 
    SelectObject(NewDC, NewHandle); 
    {$IFDEF UseDelphi}Canvas.Handle := NewDC;{$ENDIF} 
    NewBytesPerRow := (((Header.BitmapInfo.bmiHeader.biBitCount * cx) + 31) 
     and not 31) div 8; 

    {Copies the image data} 
    for Line := 0 to Min(CY - 1, Height - 1) do 
     CopyMemory(Ptr(Longint(NewImageData) + (Longint(CY) - 1) * 
     NewBytesPerRow - (Line * NewBytesPerRow)), Scanline[Line], 
     Min(NewBytesPerRow, Header.BytesPerRow)); 

    {Build array for alpha information, if necessary} 
    if (Header.ColorType = COLOR_RGBALPHA) or 
     (Header.ColorType = COLOR_GRAYSCALEALPHA) then 
    begin 
     GetMem(NewImageAlpha, CX * CY); 
     Fillchar(NewImageAlpha^, CX * CY, 255); 
     for Line := 0 to Min(CY - 1, Height - 1) do 
     CopyMemory(Ptr(Longint(NewImageAlpha) + (Line * CX)), 
     AlphaScanline[Line], Min(CX, Width)); 
     FreeMem(Header.ImageAlpha); 
     Header.ImageAlpha := NewImageAlpha; 
    end; 

    {$IFDEF Store16bits} 
    if (Header.BitDepth = 16) then 
    begin 
     GetMem(NewImageExtra, CX * CY); 
     Fillchar(NewImageExtra^, CX * CY, 0); 
     for Line := 0 to Min(CY - 1, Height - 1) do 
     CopyMemory(Ptr(Longint(NewImageExtra) + (Line * CX)), 
     ExtraScanline[Line], Min(CX, Width)); 
     FreeMem(Header.ExtraImageData); 
     Header.ExtraImageData := NewImageExtra; 
    end; 
    {$ENDIF} 

    {Deletes the old image} 
    DeleteObject(Header.ImageHandle); 
    DeleteDC(Header.ImageDC); 

    {Prepares the header to get the new image} 
    Header.BytesPerRow := NewBytesPerRow; 
    Header.IHDRData.Width := CX; 
    Header.IHDRData.Height := CY; 
    Header.ImageData := NewImageData; 

    {Replaces with the new image} 
    Header.ImageHandle := NewHandle; 
    Header.ImageDC := NewDC; 
    end 
    else 
    {The new size provided is invalid} 
    RaiseError(EPNGInvalidNewSize, EInvalidNewSize) 

end; 

SmoothResize उपयोग कर रहा हूँ गुस्तावो दाऊद द्वारा

procedure SmoothResize(apng:tpngobject; NuWidth,NuHeight:integer); 
var 
    xscale, yscale   : Single; 
    sfrom_y, sfrom_x  : Single; 
    ifrom_y, ifrom_x  : Integer; 
    to_y, to_x    : Integer; 
    weight_x, weight_y  : array[0..1] of Single; 
    weight     : Single; 
    new_red, new_green  : Integer; 
    new_blue, new_alpha : Integer; 
    new_colortype   : Integer; 
    total_red, total_green : Single; 
    total_blue, total_alpha: Single; 
    IsAlpha    : Boolean; 
    ix, iy     : Integer; 
    bTmp : TPNGObject; 
    sli, slo : pRGBLine; 
    ali, alo: pbytearray; 
begin 
    if not (apng.Header.ColorType in [COLOR_RGBALPHA, COLOR_RGB]) then 
    raise Exception.Create('Only COLOR_RGBALPHA and COLOR_RGB formats' + 
    ' are supported'); 
    IsAlpha := apng.Header.ColorType in [COLOR_RGBALPHA]; 
    if IsAlpha then new_colortype := COLOR_RGBALPHA else 
    new_colortype := COLOR_RGB; 
    bTmp := Tpngobject.CreateBlank(new_colortype, 8, NuWidth, NuHeight); 
    xscale := bTmp.Width/(apng.Width-1); 
    yscale := bTmp.Height/(apng.Height-1); 
    for to_y := 0 to bTmp.Height-1 do begin 
    sfrom_y := to_y/yscale; 
    ifrom_y := Trunc(sfrom_y); 
    weight_y[1] := sfrom_y - ifrom_y; 
    weight_y[0] := 1 - weight_y[1]; 
    for to_x := 0 to bTmp.Width-1 do begin 
     sfrom_x := to_x/xscale; 
     ifrom_x := Trunc(sfrom_x); 
     weight_x[1] := sfrom_x - ifrom_x; 
     weight_x[0] := 1 - weight_x[1]; 

     total_red := 0.0; 
     total_green := 0.0; 
     total_blue := 0.0; 
     total_alpha := 0.0; 
     for ix := 0 to 1 do begin 
     for iy := 0 to 1 do begin 
      sli := apng.Scanline[ifrom_y + iy]; 
      if IsAlpha then ali := apng.AlphaScanline[ifrom_y + iy]; 
      new_red := sli[ifrom_x + ix].rgbtRed; 
      new_green := sli[ifrom_x + ix].rgbtGreen; 
      new_blue := sli[ifrom_x + ix].rgbtBlue; 
      if IsAlpha then new_alpha := ali[ifrom_x + ix]; 
      weight := weight_x[ix] * weight_y[iy]; 
      total_red := total_red + new_red * weight; 
      total_green := total_green + new_green * weight; 
      total_blue := total_blue + new_blue * weight; 
      if IsAlpha then total_alpha := total_alpha + new_alpha * weight; 
     end; 
     end; 
     slo := bTmp.ScanLine[to_y]; 
     if IsAlpha then alo := bTmp.AlphaScanLine[to_y]; 
     slo[to_x].rgbtRed := Round(total_red); 
     slo[to_x].rgbtGreen := Round(total_green); 
     slo[to_x].rgbtBlue := Round(total_blue); 
     if isAlpha then alo[to_x] := Round(total_alpha); 
    end; 
    end; 
    apng.Assign(bTmp); 
    bTmp.Free; 
end; 

धन्यवाद एक बहुत, आपका दिन शुभ हो!

+6

पूछने के लिए मुझे गोली मत चलाना, लेकिन क्यों सिर्फ एक संसाधन में सभी अलग-अलग PNG का डंप नहीं के साथ संगत है फाइल करें और उन्हें इसके बजाय आवश्यकतानुसार लोड करें? जब आप पूरा कर लेंगे तो यह एक फ़ाइल है, और आपके निष्पादन योग्य संसाधन संसाधन में पैक हो जाती है ... संग्रहित पीएनजी लोड करने के लिए कोड की एक पंक्ति, जितनी आसान हो जाती है? – LaKraven

+0

@ लैक्रावेन मुझे पता था कि कोई यह पूछेगा! :/लेकिन मुझे छोटे पीएनजी को छोटे से टुकड़े करने और उनके साथ काम करने की जरूरत है। हमेशा की तरह nodoby यहाँ मदद करने के लिए ... –

+0

ठीक है, तो एक दृष्टिकोण (हालांकि नहीं सबसे खूबसूरत, मुझे यकीन है) पुनरावृत्ति करने के लिए एक्स और वाई खंड की, तो पिक्सेल रंग को दोहराने होगा चाहता है (RGBA अल्फा बनाए रखने के लिए) अपने नए पीएनजी कंटेनर उदाहरण पर। यह निश्चित रूप से आपको अपने "सेगमेंट" के शीर्ष, नीचे, बाएं और दाएं समन्वय को जानने की आवश्यकता होगी। – LaKraven

उत्तर

11

यहाँ एक नमूना एक 'SlicePNG' से संशोधित कोड है ("यह समारोह एक बड़ी PNG फ़ाइल स्लाइस (जैसे छोटे, समान रूप से आकार मे चित्र में एक उपकरण पट्टी के लिए सभी छवियों) के साथ एक छवि") प्रक्रिया elsewhere पाया:

procedure CropPNG(Source: TPNGObject; Left, Top, Width, Height: Integer; 
    out Target: TPNGObject); 

    function ColorToTriple(Color: TColor): TRGBTriple; 
    begin 
    Color := ColorToRGB(Color); 
    Result.rgbtBlue := Color shr 16 and $FF; 
    Result.rgbtGreen := Color shr 8 and $FF; 
    Result.rgbtRed := Color and $FF; 
    end; 

var 
    X, Y: Integer; 
    Bitmap: TBitmap; 
    BitmapLine: PRGBLine; 
    AlphaLineA, AlphaLineB: pngimage.PByteArray; 
begin 
    if (Source.Width < (Left + Width)) or (Source.Height < (Top + Height)) then 
    raise Exception.Create('Invalid position/size'); 

    Bitmap := TBitmap.Create; 
    try 
    Bitmap.Width := Width; 
    Bitmap.Height := Height; 
    Bitmap.PixelFormat := pf24bit; 

    for Y := 0 to Bitmap.Height - 1 do begin 
     BitmapLine := Bitmap.Scanline[Y]; 
     for X := 0 to Bitmap.Width - 1 do 
     BitmapLine^[X] := ColorToTriple(Source.Pixels[Left + X, Top + Y]); 
    end; 

    Target := TPNGObject.Create; 
    Target.Assign(Bitmap); 
    finally 
    Bitmap.Free; 
    end; 

    if Source.Header.ColorType in [COLOR_GRAYSCALEALPHA, COLOR_RGBALPHA] then begin 
    Target.CreateAlpha; 
    for Y := 0 to Target.Height - 1 do begin 
     AlphaLineA := Source.AlphaScanline[Top + Y]; 
     AlphaLineB := Target.AlphaScanline[Y]; 
     for X := 0 to Target.Width - 1 do 
     AlphaLineB^[X] := AlphaLineA^[X + Left]; 
    end; 
    end; 
end; 

नमूना कॉल:

var 
    Png: TPNGObject; 
    CroppedPNG: TPNGobject; 
begin 
    PNG := TPNGObject.Create; 
    PNG.LoadFromFile('..\test.png'); 

    CropPNG(PNG, 30, 10, 60, 50, CroppedPNG); 
    CroppedPNG.SaveToFile('..\croptest.png'); 
+0

OMFG, धन्यवाद = 3, मैं तुम्हें एक :)))) के मालिक हैं –

+0

@Sertac, अब इस बारे में सोच, नहीं होगा 'StretchDIBits' का उपयोग करना और केवल छवि शीर्षलेख को संशोधित करना संभव है? सादगी के लिए – TLama

+2

+1। @ टीलामा, मुझे यह भी विश्वास है कि यह 'टीबीटमैप' के उपयोग के बिना 'बिल्डबैंक' के साथ शुरू करके और 'स्कैनलाइन' और 'अल्फास्केलाइन' को नए पीएनजी में कॉपी करके किया जा सकता है। लेकिन मैं वास्तव में आज कुछ भी कोशिश करने के लिए बहुत आलसी हूं;) – kobik

1

मैं सिर्फ लोड एक png libpng उपयोग करने के लिए लेखन कोड की कोशिश की है। यह काम करने के लिए बहुत भयानक है।

imlib2 का उपयोग कर PNG फ़ाइलें अनुवाद की देखभाल करने के लिए प्रयास करें। जाहिर है, इसमें Delphi binding है।

यदि आप वास्तव में अटक आप Inage Magick के अलग निष्पादन योग्य छवि फसल करने के लिए इस्तेमाल कर सकते हैं तो।

11

यहाँ है एक और संस्करण (यह बहुत तेजी से काम करता है):

procedure CropPNG(Source: TPNGObject; Left, Top, Width, Height: Integer; 
    out Target: TPNGObject); 
var 
    IsAlpha: Boolean; 
    Line: Integer; 
begin 
    if (Source.Width < (Left + Width)) or (Source.Height < (Top + Height)) then 
    raise Exception.Create('Invalid position/size'); 

    Target := TPNGObject.CreateBlank(Source.Header.ColorType, 
    Source.Header.BitDepth, Width, Height); 
    IsAlpha := Source.Header.ColorType in [COLOR_GRAYSCALEALPHA, COLOR_RGBALPHA]; 
    for Line := 0 to Target.Height - 1 do 
    begin 
    if IsAlpha then 
     CopyMemory(Target.AlphaScanline[Line], 
     Ptr(LongInt(Source.AlphaScanline[Line + Top]) + LongInt(Left)), 
     Target.Width); 
    CopyMemory(Target.Scanline[Line], 
     Ptr(LongInt(Source.Scanline[Line + Top]) + LongInt(Left * 3)), 
     Target.Width * 3); 
    end; 
end; 

नोट: ऊपर कोड नए pngimage संस्करण 1.56+ (जो CreateBlank निर्माता का समर्थन करता है)

+0

यदि @Sertac प्रक्रिया विफल हो जाती है, तो मैं इसे आजमाउंगा .. –

+5

@ Sertac की विधि "विफल" नहीं होगी। यह वास्तव में अच्छा काम करता है। मैंने केवल एक विकल्प साझा किया जिसमें मध्य 'टीबीटममैप' शामिल नहीं है और तेज़ी से होना चाहिए। – kobik

+0

मैंने इसे पहले परीक्षण किया था, मैं बस इतना कह रहा हूं कि अगर कोई समस्या होगी, तो शायद मैं तुम्हारा उपयोग करूंगा। –

संबंधित मुद्दे