NSImage skalieren

  • NSImage skalieren

    Hallo Leute!

    Ich lese ein JPEG über ein open-Panel ein. Das speicher ich mir als NSImage.
    Meine Frage ist nun:
    Wie kann ich dieses Bild am besten runterskalieren? Es ist 3000*2000px groß.
    Gibt es sowas wie [NSImage* scaleWithFactor:x]; oder so? Ich habe leider
    auf Anhieb nichts gefunden.

    Viele Grüße und vielen Dank!
  • Danke für den Link!

    Es funktioniert auch.
    Komisch nur, dass ich das NSImage nach dem verkleinern nicht mehr in mein Array speichern
    kann...
    Hier mal mein Code:
    // hilfsBild wird allociert und mit dem Inhalt vom Arrayobjekt gefüllt
    hilfsBild = [[NSImage alloc] init];
    hilfsBild = [imageArray objectAtIndex:[imageArray count]-1];
    // Ein NSData Object vom Hilsbild erstellen
    hilfsData = [[NSData alloc] init];
    hilfsData = [hilfsBild TIFFRepresentation];
    // Eine BitmapRepresentation vom Bild erstellen
    hilfsRep = [[NSBitmapImageRep alloc] initWithData:hilfsData];
    // Die Breite und Höhe des Bildes bestimmen
    float higNeu;
    float widAlt = [hilfsRep pixelsWide];
    float higAlt = [hilfsRep pixelsHigh];
    // Die neue Höhe des Bildes bestimmen
    higNeu = round(higAlt / widAlt * 720.0);
    // Das Bild wird auf die neuen Ausmasse skaliert
    //[hilfsBild setScalesWhenResized:YES]; <-- muss das?
    [hilfsBild setSize:NSMakeSize(720.0, higNeu)];
    // Das kleine Bild wird in das Array der kleinen Bilder gesteckt
    [imageArraySmall addObject:hilfsBild];
    NSLog(@"Es sind %i Bilder im kleinen Array!\n", [imageArraySmall count]);
    // Das kleine Bild wird im großen Anzeigefenster angezeigt
    [bildFenster setImage:hilfsBild];


    Das Array bleibt immer leer. :-/
    Liegt es daran, dass ich vorher mit den verschiedenen Representationen arbeite?
    Ich glaube da gehe ich einen Umweg. Kann ich auch direkt aus einem NSImage eine
    NSBitmapRepresentation machen ohne Umweg über NSData?
    Hab das aus der Doku nicht anders herausbekommen.
  • mal alle deine teilweisen schweren ähm Obejctiv C schwächen ausser acht gelassen

    bist du dir den sicher das in dem imageArray auch wirklich ein bild enthalten ist?
    prüfe doch mal ob nicht vllt schon diese zeile:

    Quellcode

    1. hilfsBild = [imageArray objectAtIndex:[imageArray count]-1];


    fehl schlägt...

    und lies dein buch bitte etwas aufmerksamer was objekt erzeugung / deklaration und der gleichen angeht ^^;
    snafu
    :() { :|: &};:
    sometimes i dream in hex
    Obey gravity! Because its a law!
  • Ja, die Zeile macht was sie sollte.
    Denn ich gebe ja am Ende auch das Bild im Fenster aus und das klappt.
    Du kannst mir ruhig meine Schwächen zeigen, darüber wäre ich dir sehr dankbar.
    Schreib einfach was falsch ist und ich schaue nach wie ich es besser machen könnte.
    Nach ein paar Tagen Obj-C ist man nunmal noch kein Programmier-Gott :-/
  • nun es ist nicht bös gemeint aber stellenweise wirkt es sehr zusammengestoppelt

    wenn dein bild im fenster erscheint aber die logzeile keine ergebnis ausliefert ist möglicherweise dein "kleines" array als gesamtes garnicht mehr vorhanden?

    mal nur den ersten sehr offensichtlichen fehler angesprochen:

    Quellcode

    1. hilfsBild = [[NSImage alloc] init];
    2. hilfsBild = [imageArray objectAtIndex:[imageArray count]-1];

    in der ersten zeile da oben erzeugst du ein objekt
    in der art und weise mit alloc init erzeugst du es ausserdem so das du für sein leben verantwortlich bist - also unter anderem auch wie es wieder zerstört wird

    aber - in der zweiten zeile überschreibst du einfach die variable die dein einziger anhaltspunkt auf dieses objekt ist mit einem neuen objekt welches dir dort aus dem array geliefert wird

    damit hast du zumindest ein nutzloses objekt erzeugt was nun sinnlos und unerreichbar im speicher rumliegt

    ich glaube du solltest dir noch einmal ansehen wie objekte erzeugt und verwaltet werden und auch wie man variablen und zeiger auf diese objekte erstellt und behandelt
    snafu
    :() { :|: &};:
    sometimes i dream in hex
    Obey gravity! Because its a law!
  • OK, das mit der Speicherverwaltung ist für mich noch neu...
    Habs jetzt mal so gemacht:


    - (void) openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
    {

    //Bilder in voller Auflösung ins Array schreiben:
    [imageArray addObject:[[[NSImage alloc] initWithContentsOfFile:[sheet filename]]autorelease]];
    // Ein Hilfsbild anlegen mit Inhalt des eingelesenen Bildes
    NSImage* hilfsBild = [imageArray objectAtIndex:[imageArray count]-1];
    NSData* hilfsData = [hilfsBild TIFFRepresentation];
    NSBitmapImageRep* hilfsRep = [NSBitmapImageRep imageRepWithData:hilfsData];
    // Die Breite und Höhe des Bildes bestimmen
    float higNeu;
    float widAlt = [hilfsRep pixelsWide];
    float higAlt = [hilfsRep pixelsHigh];
    // Die neue Höhe des Bildes bestimmen
    higNeu = round(higAlt / widAlt * 720.0);
    // Das Bild wird auf die neuen Ausmasse skaliert
    //[hilfsBild setScalesWhenResized:YES];
    [hilfsBild setSize:NSMakeSize(720.0, higNeu)];
    // Das kleine Bild wird in das Array der kleinen Bilder gesteckt
    [imageArraySmall addObject:hilfsBild];
    NSLog(@"Es sind %i Bilder im kleinen Array!\n", [imageArraySmall count]);
    // Das kleine Bild wird im großen Anzeigefenster angezeigt
    [bildFenster setImage:hilfsBild];
    }



    Ist das von der Speicherverwaltung her nun besser?
    Ich habe doch jetzt eine Factoryinitialisierung benutzt, stimmts? Da wird der Speicher ja
    automatisch wieder freigegeben weil es ein autorelease mit sich bringt.
  • Danke für den Tipp!

    Quellcode

    1. - (void) openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
    2. {
    3. //Bilder in voller Auflösung ins Array schreiben:
    4. [imageArray addObject:[[[NSImage alloc] initWithContentsOfFile:[sheet filename]]autorelease]];
    5. // Ein Hilfsbild anlegen mit Inhalt des eingelesenen Bildes
    6. NSImage* hilfsBild = [imageArray objectAtIndex:[imageArray count]-1];
    7. NSData* hilfsData = [hilfsBild TIFFRepresentation];
    8. NSBitmapImageRep* hilfsRep = [NSBitmapImageRep imageRepWithData:hilfsData];
    9. // Die Breite und Höhe des Bildes bestimmen
    10. float higNeu;
    11. float widAlt = [hilfsRep pixelsWide];
    12. float higAlt = [hilfsRep pixelsHigh];
    13. // Die neue Höhe des Bildes bestimmen
    14. higNeu = round(higAlt / widAlt * 720.0);
    15. // Das Bild wird auf die neuen Ausmasse skaliert
    16. //[hilfsBild setScalesWhenResized:YES];
    17. [hilfsBild setSize:NSMakeSize(720.0, higNeu)];
    18. // Das kleine Bild wird in das Array der kleinen Bilder gesteckt
    19. [imageArraySmall addObject:hilfsBild];
    20. NSLog(@"Es sind %i Bilder im kleinen Array!\n", [imageArraySmall count]);
    21. // Das kleine Bild wird im großen Anzeigefenster angezeigt
    22. [bildFenster setImage:hilfsBild];
    23. }
    Alles anzeigen
  • Nein ich habe es so gemacht:

    Quellcode

    1. - (id)init {
    2. self = [super init];
    3. imageArray = [[NSMutableArray alloc] init];
    4. imageArraySmall = [[NSMutableArray alloc] init];
    5. return self;
    6. }

    Es funktioniert so, ist aber dennoch nicht optimal, da ich mich ums releasen kümmern muss?
    Wie hättest du es gemacht?
    Ich habe in der Doku nur diesen einen convenience Allocator gefunden:

    Quellcode

    1. + (id)arrayWithCapacity:(unsigned)numItems

    Dann muss ich aber doch schon vorher wissen wieviele Elemente ich haben werde, oder?

    Zum Programm:
    Komischerweise speichert er mir jetzt trotzdem die großen Dateien ins imageArraySmall und nicht die verkleinerten :-((
  • Du kannst einfach -array(NSArray) verwenden, da NSArray die Superklasse von NSMutableArray ist. Davon unabhängig ist die Kapazität aber nur ein Hinweis an NSArray. Du darfst sie überschreiten.

    Hast du denn SetSclaesWhenReiszed: wieder hereingenommen?

    Lies dir dazu übrigens mal die Dokumentation durch.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • In der ersten Zuweisung weist Du Dein Bild dem ersten 'array' zu, um es sofort zurück zu holen (auch mit [array lastObject] möglich).
    Das rep benutzt Du nur, um die Größe zu erfragen. Die neue Skalierung wird dann mit 'setSize' auf das ursprüngliche, und einzige Bild, angewendet. Das 'rep' wird effektiv nicht genutzt, und würde gar nicht, wenn Du '[image size] ' nimmst.

    In beiden Feldern ist dasselbe NSImage mit neuer Größe.
    I would be embarrassed if they did not spy on me.
  • Original von Tom9811
    Du kannst einfach -array(NSArray) verwenden, da NSArray die Superklasse von NSMutableArray ist. Davon unabhängig ist die Kapazität aber nur ein Hinweis an NSArray. Du darfst sie überschreiten.


    Hast du denn SetSclaesWhenReiszed: wieder hereingenommen?

    Lies dir dazu übrigens mal die Dokumentation durch.


    Zu den Arrays: Was würdest du als erfahrener Programmierer für eine init Verwenden? Ich sehe
    da noch nicht die Vor- und Nachteile, für mich ist das alles gleich, da alles irgendwie funktioniert.
    Warum sollte ich eine convenient benutzen? Weil es dann weniger arbeit mit dem releasen ist?

    Also das SetScalesWhenResized habe ich wieder reingenommen. Bringt aber nix.
  • Original von longW
    In der ersten Zuweisung weist Du Dein Bild dem ersten 'array' zu, um es sofort zurück zu holen (auch mit [array lastObject] möglich).
    Das rep benutzt Du nur, um die Größe zu erfragen. Die neue Skalierung wird dann mit 'setSize' auf das ursprüngliche, und einzige Bild, angewendet. Das 'rep' wird effektiv nicht genutzt, und würde gar nicht, wenn Du '[image size] ' nimmst.

    In beiden Feldern ist dasselbe NSImage mit neuer Größe.

    W.


    Ja das Rep benutze ich nur um die Größe zu holen weil das mit image size nicht funktioniert hat. Das funktioniert nämlich nur wenn die Bilder 72dpi haben.

    Ich habe nun in beiden Arrays die Bilder in voller Auflösung. :(
  • Wir wissen nicht, was dieser junge Mann empfiehlt. Wir aber empfehlen Togal.
    Sll heißen: [NSArray array], wenn du gar keine Ahnung hast, wie viele darin landen.
    Zum ganzen Thema habe ich einen Artikel geschrieben:
    macentwicklerwelt.net/doku.php?id=wiki:speicherverwaltung

    Zur Funktionalität hat dir longW ja schon etwas geschrieben. Lies dir trotzdem mal die Dokumentation durch.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?